PopupWindow在开发中也是很常见的一个控件,由于多数情况下PopupWindow都是弹出一个列表框,从Android3.0开始官方提供了两个专门用于弹出列表的弹框ListPopupWindow和PopupMenu,如果想要支持更低的版本可以使用support v7中相应的类。
创建PopupWindow有两种类型的构造方法,一种是传统方式创建View的方式,另外一种是直接传进一个View的构造方式。
//方式一 PopupWindow(Contextcontext) PopupWindow(Contextcontext, AttributeSetattrs) PopupWindow(Contextcontext, AttributeSetattrs, int defStyleAttr) PopupWindow(Contextcontext, AttributeSetattrs, int defStyleAttr, int defStyleRes) //方式二 PopupWindow(ViewcontentView) PopupWindow(int width, int height) PopupWindow(ViewcontentView, int width, int height) PopupWindow(ViewcontentView, int width, int height, boolean focusable)
PopupWindow更类似与一个工具类,在工具类中存入一个View,在操作的时候弹出或销毁该View。查看源码我们也可以看出来PopupWindow并没有继承自View,因此在使用的时候与View还是有很显著差别的,View可以定义子在布局文件中,但是没有哪个开发者将PopupWindow放在布局文件中。在传入上下文Context的时候跟创建View类似,如果创建一个View需要传入一个Context实例,方式一不用多说了,在方式二中只要传入一个View同样可以通过View中getContext方法获取一个Context实例。
在创建一个PopupWindow的时候有三个最基本的属性必须设置,contentView、width和height,这里具体的为什么后面再做分析,虽然已经传入了View,但是View的高度是由父控件决定的,在创建的时候是不知道它的父控件是谁的,因此宽高都是未知的,如果不设置是显示不出来PopupWindow的。
Viewview=View.inflate(context, R.layout.layout_popup,null); popupWindow.setWidth(width); popupWindow.setHeight(height); popupWindow.setContentView(view);
这里用了三行代码才设置完毕所必须的属性,事实上使用方式二中的第3个和第4个构造方法可以直接构造出需要显示的PopupWindow,focusable这个属性不是必须的,但是在交互的时候缺少该属性也会引发很奇葩的问题,在后面也会介绍。
设置PopupWindow显示位置主要有两种类型showAsDropDown和showAtLocation:
showAsDropDown(Viewanchor) showAsDropDown(Viewanchor, int xoff, int yoff) showAsDropDown(Viewanchor, int xoff, int yoff, int gravity)//API 19新增 showAtLocation (Viewparent, int gravity, int x, int y) showAsDropDown(Viewanchor, int xoff, int yoff, int gravity)
该方法是设置相对于anchor的位置,如果showAsDropDown只有一个参数,就是相对于anchor左下方,xoff和yoff是相对anchor左下方为基点在x方向移动xoff像素,在y方向移动yoff像素,gravity与showAtLocation中gravity属性是有本质区别的,该方法的gravity是相对于anchor方位。
showAtLocation (View parent, int gravity, int x, int y)
该方法是相对于屏幕位置,位置展示跟parent基本没有关系,parent只是为了获取一个WindowToken,用于检索出该View所处的Window窗体,然后设置PopupWindow的布局参数到WindowManager.LayoutParams上面。
public void showAtLocation(Viewparent, int gravity, int x, int y) { showAtLocation(parent.getWindowToken(), gravity, x, y); } public void showAtLocation(IBindertoken, int gravity, int x, int y) { //... final WindowManager.LayoutParams p = createPopupLayoutParams(token); preparePopup(p); // Only override the default if some gravity was specified. if (gravity != Gravity.NO_GRAVITY) { p.gravity = gravity; } p.x = x; p.y = y; invokePopup(p); } //下面方法来自View中方法 /** * Retrieve a unique token identifying the window this view is attached to. * @return Return the window's token for use in * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. */ public IBindergetWindowToken() { return mAttachInfo != null ? mAttachInfo.mWindowToken : null; }
dismiss () setAnimationStyle(int animationStyle) setOutsideTouchable(boolean touchable) setBackgroundDrawable(Drawablebackground) setFocusable(boolean focusable)
比较常用的方法也就这么多了,接下来介绍Popup简单使用。
本文实例只是为了演示PopupWindow基本使用,布局都是使用较简单的方式呈现。
先看一下布局文件,非常简单内部仅有一个View设置一个背景色。
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Viewandroid:layout_height="match_parent" android:background="#ff4081" android:layout_width="match_parent"/> </LinearLayout>
下面创建一个PopupWindow,这里使用两种创建方式,究竟使用哪一种方式看个人习惯而定。
Viewview=View.inflate(this,R.layout.layout_popup,null); //方式一 popupWindow=new PopupWindow(this); popupWindow.setContentView(view); popupWindow.setWidth(400); popupWindow.setHeight(200); popupWindow.setFocusable(true); //方式二 popupWindow=new PopupWindow(view, 400, 200, true); popupWindow.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#00000000"))); popupWindow.showAsDropDown(btn);
showAsDropDown(View anchor)已经显示在了左下方,其实该方法中X方向位移xoff和Y方向位移yoff都是0,PopupWindow中实现源代码如下:
/** * Display the content view in a popup window anchored to the bottom-left * corner of the anchor view. If there is not enough room on screen to show * the popup in its entirety, this method tries to find a parent scroll * view to scroll. If no parent scroll view can be scrolled, the * bottom-left corner of the popup is pinned at the top left corner of the * anchor view. * * @param anchor the view on which to pin the popup window * * @see #dismiss() */ public void showAsDropDown(Viewanchor) { showAsDropDown(anchor, 0, 0); }
想要距离anchor View在X方向和Y方向平移,只需要将xoff和yoff传入具体的数值即可。
该方法是设置PopupWindow相对于窗口位置,通过gravity参数设置。有部分开发者使用PopupWindow来设计弹出框或者仿写类似QQ弹出菜单都是借助于该方法,然后使用setAnimationStyle设置炫酷的动画。例如从窗口下侧显示使用Gravity.BOTTOM或者显示在屏幕中央使用Gravity.CENTER。
PopupWindow设置动画跟设置普通View的动画不同,PopupWindow直译弹出窗体,所以使用动画使用是转场动画windowAnimation,进入动画android:windowEnterAnimation和退出动画android:windowExitAnimation。
设置底部进入动画
<?xmlversion="1.0" encoding="utf-8"?> <setxmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="200" android:fromYDelta="100%" android:toYDelta="0%"/> </set>
设置底部退出动画
<?xmlversion="1.0" encoding="utf-8"?> <setxmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="200" android:fromYDelta="0%" android:toYDelta="100%"/> </set>
然后在style.xml文件中设置转场动画
<stylename="CustomPopAnim"> <itemname="android:windowEnterAnimation">@anim/slide_from_bottom</item> <itemname="android:windowExitAnimation">@anim/slide_to_bottom</item> </style>
PopupWindow隐藏调用的是dismiss方法,如果想在PopupWindow隐藏的时候处理其它事件可以设置事件监听器。
popupWindow.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss() { //TODO } });
这篇文章先完成到这里,有关其它几个常用的方法在随后的文章继续,同样ListPopupWindow和PopupMenu以及与Dialog的区别也在下一篇文章介绍。