上一篇中,简单讲解了PopupWindow的简单使用,如果还有人还没看的,可以先去看看上一篇android之PopupWinow详解一。
在很多时候android给我们提供的PopupWindow的这些方法和样式并不能满足我们实际开发的需要,就比如如果我们想从底部弹出一个对话框或者菜单什么的来供用户选择,同时点击PopupWindow外的区域时弹出窗口隐藏和PopupWindow弹出时,剩余父窗口变成半透明等效果,这个时候我们就可以通过自定义PopupWindow来实现,如,想实现如下效果:
首先如果想从底部弹出一个对话框或者菜单的话,我们可以通过PopupWindow提供的showAtLocation(View parent,int gravity,int x,int y)方法来实现,其中:
第一个参数parent指的是父容器,也可以是父容器的某个组件,通常情况下可以通过findViewById()方法来取得对应的组件;
第二个参数gravity指的是PopupWindow弹出的方向,可以有Gravity.BOTTOM表示从底部弹出,Gravity.TOP表示从顶部弹出,Gravity.LEFT表示从左边弹出,Gravity.RIGHT表示从右边弹出;
第三个参数x指的是x轴方向上到原点的水平距离,如果PopupWindow的宽度是占满父容器宽度的话则不起作用;
第四个参数y指的是y轴方向上到底部的垂直距离,如果想实现从底部弹出来的话,则设置为0。
代码如下所示:
pw.showAtLocation(findViewById(R.id.ll_root), Gravity.BOTTOM, 0, 0);
如果想实现PopupWindow弹出时,剩余父容器变为半透明的话,可以通过如下代码将alpha透明度设置为0.5即可:
/** * 设置父窗口的透明度 * @param alpha 透明度 */ private void setParentViewAlpha(float alpha) { WindowManager.LayoutParams params = getWindow().getAttributes(); params.alpha = alpha; getWindow().setAttributes(params); }
当然,如果想在PopupWindow弹出窗口隐藏时,父窗口变为原先状态的话,只需要将透明度变为1即可。
最后,如果想实现当点击PopupWindow弹出窗口外的区域时,将PopupWindow隐藏的话,可以通过如下代码实现:
pw.setTouchable(true); pw.setOutsideTouchable(true); pw.setBackgroundDrawable(new BitmapDrawable(getResources(), (Bitmap) null));
其中上面三个方法缺一不可,对于为什么要设置setBackgroundDrawable,这个我也不清楚,上网查了半天,都说不清楚,但是有一点可以肯定的是,如果不设置的话,就实现不了点击区域外时隐藏弹出窗口的效果。
另外,还有一点需要注意的是,此时如果不小心点击了PopupWindow区域外也就是剩余父窗口中的文本输入框EditText时,虽然PopupWindow会隐藏掉,但是由于EditText获取到了焦点,因此会弹出键盘,这样的话明显不是我们想要的结果,并且,如果有设置PopupWindow弹出时剩余父窗口变为半透明的话,PopupWindow隐藏时父窗口也不会变为原先的半透明,因此我们还应该为PopupWindow设置如下属性:
pw.setFocusable(true); pw.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { //设置父窗口的透明度为正常状态 setParentViewAlpha(1.0f); } });
这里需要注意的是,如果想使用setOnDismissListener事件,必须先将PopupWindow的setFocusable设置为true,否则该隐藏事件不起作用,这样的话,就可以解决当不小点击PopupWindow区域外的EditText时弹出键盘和父窗口透明度不改变的问题了。
另外,还可以在通过如下代码设置PopupWindow弹出时的动画效果:
//为PopupWindow添加动画 pw.setAnimationStyle(R.style.PopupWindow_Animation);
这里用到的PopupWindow_Animation的style属性如下所示:
<style name="PopupWindow_Animation"> <item name="android:windowEnterAnimation">@anim/pw_bottom_in</item> <item name="android:windowExitAnimation">@anim/pw_bottom_out</item> </style>
上面属性中分别引用了pw_bottom_in和pw_bottom_out两个动画属性文件,代码分别如下所示:
pw_bottom_in.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromYDelta="100.0%" android:toYDelta="0.0" android:duration="250" /> </set>
pw_bottom_out.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromYDelta="0.0" android:toYDelta="100.0%" android:duration="250" /> </set>
至此,所需要实现的效果原理和涉及到的知识就讲完了,设置PopupWindow的主要代码如下所示:
private GridView gv_items; private Button btn_cancel, btn_ok; private PopupWindow pw; private PopupWindowAdapter adapter; /** * 显示弹出窗口 */ private void showPopupWindow() { View view = View.inflate(this, R.layout.activity_popupwindow, null); gv_items = (GridView) view.findViewById(R.id.gv_items); btn_cancel = (Button) view.findViewById(R.id.btn_cancel); btn_ok = (Button) view.findViewById(R.id.btn_ok); pw = new PopupWindow(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true); String[] items = new String[]{"北京", "上海", "天津", "南京", "广州", "深圳", "杭州", "南昌", "武汉"}; List<String> cities = getSelectedFromFile(); if (cities != null) { adapter = new PopupWindowAdapter(this, items, cities); } else { adapter = new PopupWindowAdapter(this, items, null); } gv_items.setAdapter(adapter); pw.setTouchable(true); pw.setOutsideTouchable(true); pw.setFocusable(true); pw.setBackgroundDrawable(new BitmapDrawable(getResources(), (Bitmap) null)); pw.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { setParentViewAlpha(1.0f); } }); //设置父窗口为半透明 this.setParentViewAlpha(0.5f); //为PopupWindow添加动画 pw.setAnimationStyle(R.style.PopupWindow_Animation); pw.showAtLocation(findViewById(R.id.ll_root), Gravity.BOTTOM, 0, 0); } /** * 关闭PopupWindow */ private void closePoupWindow() { if (pw != null && pw.isShowing()) { pw.dismiss(); pw = null; this.setParentViewAlpha(1.0f); } } /** * 设置父窗口的透明度 * * @param alpha 透明度 */ private void setParentViewAlpha(float alpha) { WindowManager.LayoutParams params = getWindow().getAttributes(); params.alpha = alpha; getWindow().setAttributes(params); }源码下载