一、线程中使用Handler执行轮询任务
1、添加任务
LinkedList<Runnable> mTaskQueue = new LinkedList<>(); private synchronized void addTask(Runnable runnable) { mTaskQueue.add(runnable); try { if(mPoolThreadHandler == null) { // 请求为0阻塞,无法获取信号量则阻塞 mSemaphoreThreadHandler.acquire(); } } catch (InterruptedException e) { } mPoolThreadHandler.sendEmptyMessage(0); }
由于初始化init方法有可能没有执行完就执行添加任务的方法,那么Handler为null无法执行,这里使用信号量来管理。
2、轮询任务
// 后台轮询线程 mPoolThread = new Thread(new Runnable() { @Override public void run() { Looper.prepare(); mPoolThreadHandler = new Handler(){ // 线程池中取任务执行 @Override public void handleMessage(Message msg) { mThreadPool.execute(getTask()); try { // 当信号量为3,那么第4个时就会阻塞 mSemaphoreThreadPool.acquire(); } catch (InterruptedException e) { } } }; // 轮询Handler已经初始化完毕,释放信号量 mSemaphoreThreadHandler.release(); Looper.loop();// 轮询 } }); mPoolThread.start();
3、执行任务
固定线程数量的线程池中执行,使用信号量管理任务,一个task执行完释放一个信号量,轮询线程中获取信号量,如果取不到就会阻塞
ExecutorService mThreadPool = Executors.newFixedThreadPool(threadCount); Semaphore mSemaphoreThreadPool = new Semaphore(threadCount); // Task new Runnable(){ @Override public void run() { // 加载图片 // 获取图片大小 ImageSize imageSize = getImageViewSize(imageView); // 压缩图片 Bitmap bm = decodeSampledBitmapFromPath(path, imageSize.width, imageSize.height); // 图片加载到缓存 addBitmapToLruCache(path, bm); Message message = Message.obtain(); ImageHolder holder = new ImageHolder(); holder.bitmap = bm; holder.path = path; holder.imageView = imageView; message.obj = holder; mUIHandler.sendMessage(message); // 释放一个信号量 mSemaphoreThreadPool.release(); } }
二、定义PopWindow
1、设置宽高、焦点、背景
2、显示位置,如果下方位置不够显示,则会显示在上方
popwindow.showAsDropDown(button, 0, 0);
三、源码
public class MainActivity extends AppCompatActivity { private int mMaxCount; private List<String> mImgs; private File mCurrentDir; private List<FolderBean> list = new ArrayList<>(); private ProgressDialog pd; private Handler mHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { pd.dismiss(); data2View(); return true; } }); private GridView gridView; private TextView text1; private TextView text2; private RelativeLayout relativeLayout; private ListPopwindow popwindow; private ImageAdapter mAdapter; private Button button; private void data2View() { if(mCurrentDir == null){ Toast.makeText(this, "未扫描到图片", Toast.LENGTH_LONG).show(); return; } mImgs = Arrays.asList(mCurrentDir.list()); mAdapter = new ImageAdapter(this, mImgs, mCurrentDir.getAbsolutePath()); gridView.setAdapter(mAdapter); text1.setText("数量:"+mMaxCount); text2.setText(mCurrentDir.getName()); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); relativeLayout = (RelativeLayout) findViewById(R.id.relative_layout); button = (Button) findViewById(R.id.button); text1 = (TextView) findViewById(R.id.text_1); text2 = (TextView) findViewById(R.id.text_2); gridView = (GridView) findViewById(R.id.grid_view); initData(); initPopWindow(); relativeLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { popwindow.setAnimationStyle(R.style.dir); popwindow.showAsDropDown(button, 0, 0); // 内容区域变暗 WindowManager.LayoutParams lp = getWindow().getAttributes(); lp.alpha = 0.3f; getWindow().setAttributes(lp); } }); Handler h = new Handler(); h.postDelayed(new Runnable() { @Override public void run() { iniPopupWindow(); } }, 10000); } private void initPopWindow() { popwindow = new ListPopwindow(this, list); popwindow.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { // 内容区域变亮 WindowManager.LayoutParams lp = getWindow().getAttributes(); lp.alpha = 1.0f; getWindow().setAttributes(lp); } }); popwindow.setListemer(new ListPopwindow.OnDirSelectedListener() { @Override public void onSelected(FolderBean bean) { mCurrentDir = new File(bean.getDir()); mImgs = Arrays.asList(mCurrentDir.list(new FilenameFilter() { @Override public boolean accept(File dir, String filename) { if(filename.endsWith(".jpg")||filename.endsWith(".jpeg")||filename.endsWith(".png")){ return true; } return false; } })); mAdapter = new ImageAdapter(MainActivity.this, mImgs, mCurrentDir.getAbsolutePath()); gridView.setAdapter(mAdapter); text2.setText(mImgs.size()+""); text1.setText(bean.getName()); popwindow.dismiss(); } }); } /** * 利用contentprovide扫描图片 */ private void initData() { if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ Toast.makeText(this, "没有SD卡", Toast.LENGTH_LONG).show(); return; } pd = ProgressDialog.show(this, null, "loading..."); new Thread(){ @Override public void run() { Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; ContentResolver cr = MainActivity.this.getContentResolver(); Cursor cursor = cr.query(uri, null, MediaStore.Images.Media.MIME_TYPE+"= ? or "+MediaStore.Images.Media.MIME_TYPE+"= ?", new String[]{"image/jpeg", "image/png"}, MediaStore.Images.Media.DATE_MODIFIED); Set<String> mDirPaths = new HashSet<String>(); while(cursor.moveToNext()){ String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); File parentFile = new File(path).getParentFile(); if(parentFile == null){ continue; } // 获取当前文件夹 String dirPath = parentFile.getAbsolutePath(); FolderBean fb = null; if(mDirPaths.contains(dirPath)){ continue; } mDirPaths.add(dirPath); fb = new FolderBean(); fb.setDir(dirPath);// 目录 fb.setFirstImgPath(path);// 第一个图片地址 // 防止为null if(parentFile.list() == null){ continue; } int picSize = parentFile.list(new FilenameFilter() { @Override public boolean accept(File dir, String filename) { if(filename.endsWith(".jpg")||filename.endsWith(".jpeg")||filename.endsWith(".png")){ return true; } return false; } }).length; fb.setCount(picSize); list.add(fb); if(picSize > mMaxCount){ mMaxCount = picSize; mCurrentDir = parentFile; } } // 释放 cursor.close(); mHandler.sendEmptyMessage(0); } }.start(); } private void iniPopupWindow() { LayoutInflater inflater = (LayoutInflater) MainActivity.this .getSystemService(LAYOUT_INFLATER_SERVICE); View layout = inflater.inflate(R.layout.popup_item, null); PopupWindow pwMyPopWindow = new PopupWindow(layout); pwMyPopWindow.setFocusable(true);// 加上这个popupwindow中的ListView才可以接收点击事件 // 控制popupwindow的宽度和高度自适应 pwMyPopWindow.setWidth(100); pwMyPopWindow.setHeight(200); // 控制popupwindow点击屏幕其他地方消失 pwMyPopWindow.setBackgroundDrawable(MainActivity.this.getResources().getDrawable( R.drawable.bg_popupwindow));// 设置背景图片,不能在布局中设置,要通过代码来设置 pwMyPopWindow.setOutsideTouchable(true);// 触摸popupwindow外部,popupwindow消失。这个要求你的popupwindow要有背景图片才可以成功,如上 pwMyPopWindow.showAsDropDown(button);// 显示 } }
public class ListPopwindow extends PopupWindow{ private int mWidth; private int mHeight; private View mContentView; private ListView mListView; private List<FolderBean> mDatas; public interface OnDirSelectedListener{ void onSelected(FolderBean bean); } public OnDirSelectedListener listemer; public void setListemer(OnDirSelectedListener listemer) { this.listemer = listemer; } public ListPopwindow(Context context, List<FolderBean> list){ calWidthAndHeight(context); mContentView = LayoutInflater.from(context).inflate(R.layout.popup, null); mDatas = list; setContentView(mContentView); setWidth(mWidth); setHeight(mHeight); setFocusable(true); setTouchable(true); // 点击外部消失 setOutsideTouchable(true); setBackgroundDrawable(new BitmapDrawable()); setTouchInterceptor(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // 点击外部 if(event.getAction() == MotionEvent.ACTION_OUTSIDE){ dismiss(); return true; } return false; } }); initView(context); initEvent(); } private void initEvent() { mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if(listemer != null){ listemer.onSelected(mDatas.get(position)); } } }); } private void initView(Context context) { mListView = (ListView) mContentView.findViewById(R.id.list_view); mListView.setAdapter(new ListDirAdapter(context, mDatas)); } /** * 计算pop宽高 * @param context */ private void calWidthAndHeight(Context context) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics d = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(d); mWidth = d.widthPixels; mHeight = (int) (d.heightPixels*0.7); } private class ListDirAdapter extends ArrayAdapter<FolderBean>{ private LayoutInflater mInflater; private List<FolderBean> mDatas; public ListDirAdapter(Context context, List<FolderBean> objects) { super(context, 0, objects); mInflater = LayoutInflater.from(context); } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if(convertView == null){ holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.popup_item, parent, false); holder.mImg = (ImageView) convertView.findViewById(R.id.imageView); holder.mDirName = (TextView) convertView.findViewById(R.id.textView); holder.mDirCount = (TextView) convertView.findViewById(R.id.textView2); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } FolderBean bean = getItem(position); holder.mImg.setImageResource(R.mipmap.pictures_no); ImageLoader.getmInstance(3, ImageLoader.Type.LIFO).loadImage( bean.getFirstImgPath(), holder.mImg); holder.mDirName.setText(bean.getName()); holder.mDirCount.setText(bean.getCount()+""); return convertView; } private class ViewHolder{ ImageView mImg; TextView mDirName; TextView mDirCount; } } }
public class ImageLoader { private static ImageLoader mInstance; private ImageLoader(){} // 图片缓存 private LruCache<String, Bitmap> mLruCache; private ExecutorService mThreadPool; // 线程池数量 private static final int default_thread_count = 1; // 队列调度方式 private Type mType = Type.LIFO; // 任务队列 private LinkedList<Runnable> mTaskQueue; // 轮询线程 private Thread mPoolThread; private Handler mPoolThreadHandler; private Handler mUIHandler; // 信号量 用于等待同步 private Semaphore mSemaphoreThreadHandler = new Semaphore(0); private Semaphore mSemaphoreThreadPool; public enum Type{ FIFO,LIFO; } public static ImageLoader getmInstance(int threadCount, Type type){ if(mInstance == null){// 过滤掉大部分处理,提高性能 synchronized (ImageLoader.class){ if(mInstance == null){ mInstance = new ImageLoader(threadCount, type); } } } return mInstance; } private ImageLoader(int threadCount, Type type){ init(threadCount, type); } /** * 初始化 * @param threadCount * @param type */ private void init(int threadCount, Type type) { // 后台轮询线程 mPoolThread = new Thread(new Runnable() { @Override public void run() { Looper.prepare(); mPoolThreadHandler = new Handler(){ // 线程池中取任务执行 @Override public void handleMessage(Message msg) { mThreadPool.execute(getTask()); try { // 当信号量为3,那么第4个时就会阻塞 mSemaphoreThreadPool.acquire(); } catch (InterruptedException e) { } } }; // 释放信号量 mSemaphoreThreadHandler.release(); Looper.loop();// 轮询 } }); mPoolThread.start(); // 获取应用最大内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheMemory = maxMemory/8; mLruCache = new LruCache<String, Bitmap>(cacheMemory){ // 测量每个图片的大小 @Override protected int sizeOf(String key, Bitmap value) { // 每行字节数*高度 return value.getRowBytes()*value.getHeight(); } }; // 线程池 mThreadPool = Executors.newFixedThreadPool(threadCount); mTaskQueue = new LinkedList<>(); mType = type; mSemaphoreThreadPool = new Semaphore(threadCount); } /** * 设置图片 * @param path * @param imageView */ public void loadImage(final String path,final ImageView imageView){ imageView.setTag(path); if(mUIHandler == null){ mUIHandler = new Handler(new Handler.Callback(){ @Override public boolean handleMessage(Message msg) { // 获取得到的图片 ImageHolder holder = (ImageHolder) msg.obj; Bitmap bitmap = holder.bitmap; ImageView iv = holder.imageView; String path = holder.path; if(iv.getTag().toString().equals(path)){ iv.setImageBitmap(bitmap); } return true; } }); } Bitmap bmp = getBitmapFromLruCache(path); if(bmp != null){ Message message = Message.obtain(); ImageHolder holder = new ImageHolder(); holder.bitmap = bmp; holder.path = path; holder.imageView = imageView; message.obj = holder; mUIHandler.sendMessage(message); }else{ addTask(new Runnable(){ @Override public void run() { // 加载图片 // 获取图片大小 ImageSize imageSize = getImageViewSize(imageView); // 压缩图片 Bitmap bm = decodeSampledBitmapFromPath(path, imageSize.width, imageSize.height); // 图片加载到缓存 addBitmapToLruCache(path, bm); Message message = Message.obtain(); ImageHolder holder = new ImageHolder(); holder.bitmap = bm; holder.path = path; holder.imageView = imageView; message.obj = holder; mUIHandler.sendMessage(message); // 释放一个信号量 mSemaphoreThreadPool.release(); } }); } } /** * 图片加入缓存 * @param path * @param bm */ private void addBitmapToLruCache(String path, Bitmap bm) { if(getBitmapFromLruCache(path) != null){ if(bm != null){ mLruCache.put(path, bm); } } } /** * 压缩图片 * @param path * @param width * @param height * @return */ private Bitmap decodeSampledBitmapFromPath(String path, int width, int height) { BitmapFactory.Options options = new BitmapFactory.Options(); // 获取图片宽高,不加载到内存中 options.inJustDecodeBounds = true; BitmapFactory.decodeFile(path, options); options.inSampleSize = caculateInSampleSize(options, width, height); options.inJustDecodeBounds = false; Bitmap bm = BitmapFactory.decodeFile(path, options); return bm; } private int caculateInSampleSize(BitmapFactory.Options options, int width, int height) { int w = options.outWidth; int h = options.outHeight; int inSampleSize = 1; if(w > width || h > height){ int widthRadio = Math.round(w*1.0f/width); int heightRadio = Math.round(h*1.0f/height); inSampleSize = Math.max(widthRadio, heightRadio); } return inSampleSize; } /** * 根据ImageView获取宽高 * @param imageView * @return */ private ImageSize getImageViewSize(ImageView imageView) { DisplayMetrics displayMetrics = imageView.getContext().getResources().getDisplayMetrics(); ImageSize imageSize = new ImageSize(); ViewGroup.LayoutParams lp = imageView.getLayoutParams(); int width = imageView.getWidth();// imageView实际宽度,未布局时没有值 if(width <= 0){ width = lp.width;// layout中声明的宽度 } if(width <= 0){ // API 16 // width = imageView.getMaxWidth();// 检查最大值 width = getImageViewFieldValue(imageView, "mMaxWidth"); } if(width <=0 ){ width = displayMetrics.widthPixels;// 屏幕宽度 } int height = imageView.getHeight();// imageView实际宽度,未布局时没有值 if(height <= 0){ height = lp.height;// layout中声明的宽度 } if(height <= 0){ // height = imageView.getMaxHeight();// 检查最大值 } if(height <=0 ){ height = displayMetrics.heightPixels;// 屏幕宽度 } imageSize.width = width; imageSize.height = height; return imageSize; } /** * 反射取属性 * @param object * @param fieldName * @return */ private static int getImageViewFieldValue(Object object, String fieldName){ int value = 0; try { Field field = ImageView.class.getDeclaredField(fieldName); field.setAccessible(true); int fieldValue = field.getInt(object); if(fieldValue > 0 && fieldValue < Integer.MAX_VALUE){ value = fieldValue; } } catch (Exception e) { } return value; } /** * 添加任务 * @param runnable */ private synchronized void addTask(Runnable runnable) { mTaskQueue.add(runnable); try { if(mPoolThreadHandler == null) { // 请求为0阻塞 mSemaphoreThreadHandler.acquire(); } } catch (InterruptedException e) { } mPoolThreadHandler.sendEmptyMessage(0); } public Runnable getTask() { if(mType == Type.FIFO){ return mTaskQueue.removeFirst(); }else if(mType == Type.LIFO){ return mTaskQueue.removeLast(); } return null; } private Bitmap getBitmapFromLruCache(String path) { return mLruCache.get(path); } private class ImageHolder{ Bitmap bitmap; ImageView imageView; String path; } private class ImageSize{ int width; int height; } }
public class ImageAdapter extends BaseAdapter { static Set<String> mSelectedImg = new HashSet<>(); private String mDirPath; private List<String> mImgPaths; private LayoutInflater mInflater; public ImageAdapter(Context context, List<String> mDatas, String dirPath){ this.mDirPath = dirPath; this.mImgPaths = mDatas; mInflater = LayoutInflater.from(context); } @Override public int getCount() { return mImgPaths.size(); } @Override public Object getItem(int position) { return mImgPaths.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { final ViewHolder holder; if(convertView == null){ convertView = mInflater.inflate(R.layout.layout, parent, false); holder = new ViewHolder(); holder.mImg = (ImageView) convertView.findViewById(R.id.id_item_image); holder.mSelect = (ImageButton) convertView.findViewById(R.id.id_item_select); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } // 初始化 holder.mImg.setImageResource(R.mipmap.pictures_no); holder.mSelect.setImageResource(R.mipmap.picture_unselected); holder.mImg.setColorFilter(null); ImageLoader.getmInstance(3, ImageLoader.Type.LIFO) .loadImage(mDirPath+"/"+mImgPaths.get(position), holder.mImg); final String filePath = mDirPath+"/"+mImgPaths.get(position); holder.mImg.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 已选择 if(mSelectedImg.contains(filePath)){ mSelectedImg.remove(filePath); holder.mImg.setColorFilter(null); holder.mSelect.setImageResource(R.mipmap.picture_unselected); }else{ mSelectedImg.add(filePath); holder.mImg.setColorFilter(Color.parseColor("#77000000")); holder.mSelect.setImageResource(R.mipmap.pictures_selected); } //notifyDataSetChanged(); } }); /*if(mSelectedImg.contains(filePath)){ holder.mImg.setColorFilter(Color.parseColor("#77000000")); holder.mSelect.setImageResource(R.mipmap.pictures_selected); }*/ return convertView; } private class ViewHolder{ ImageView mImg; ImageButton mSelect; } }
public class FolderBean { // 文件夹路径 public String dir; public String firstImgPath; public String name; public int count; public String getDir() { return dir; } public void setDir(String dir) { this.dir = dir; int lastIndexOf = this.dir.indexOf("/"); this.name = dir.substring(lastIndexOf); } public String getFirstImgPath() { return firstImgPath; } public void setFirstImgPath(String firstImgPath) { this.firstImgPath = firstImgPath; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } }
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="me.zcy.imagechoose.MainActivity"> <RelativeLayout android:id="@+id/relative_layout" android:layout_alignParentBottom="true" android:paddingLeft="12dp" android:paddingRight="12dp" android:layout_width="match_parent" android:layout_height="50dp"> <TextView android:id="@+id/text_1" android:layout_centerVertical="true" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/text_2" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout> <GridView android:id="@+id/grid_view" android:layout_above="@id/relative_layout" android:stretchMode="columnWidth" android:numColumns="3" android:verticalSpacing="3dp" android:horizontalSpacing="3dp" android:listSelector="@android:color/transparent" android:cacheColorHint="@android:color/transparent" android:layout_width="match_parent" android:layout_height="match_parent"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="New Button" android:id="@+id/button" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" /> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:layout_width="match_parent" android:layout_height="100dp" android:scaleType="centerCrop" android:src="@mipmap/pictures_no" android:id="@+id/id_item_image" /> <ImageButton android:id="@+id/id_item_select" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="false" android:layout_alignParentRight="true" android:layout_margin="3dp" android:background="@null" android:src="@mipmap/picture_unselected" /> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:background="#ffffff" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:dividerHeight="1.0px" android:divider="#eec679" android:id="@+id/list_view"/> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:layout_width="100dp" android:layout_height="100dp" android:id="@+id/imageView" android:background="@mipmap/pic_dir" android:scaleType="centerCrop" android:layout_marginLeft="35dp" android:layout_marginStart="35dp" android:layout_marginTop="27dp" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/dir_choose" android:id="@+id/imageView2" android:layout_alignParentRight="true" android:layout_margin="30dp" /> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/linearLayout" android:layout_centerVertical="true" android:layout_toLeftOf="@+id/imageView2" android:layout_toRightOf="@+id/imageView"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="New Text" android:id="@+id/textView" android:layout_marginTop="30dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="New Text" android:id="@+id/textView2" android:layout_marginTop="50dp" /> </LinearLayout> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="200" android:fromXDelta="0" android:toXDelta="0" android:fromYDelta="100%" android:toYDelta="0" /> </set>
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="200" android:fromXDelta="0" android:toXDelta="0" android:fromYDelta="0" android:toYDelta="100%" /> </set>
<style name="dir"> <item name="android:windowEnterAnimation">@anim/anim_up</item> <item name="android:windowExitAnimation">@anim/anim_down</item> </style>
运行效果