Android PopupWindow使用方法小结
前几天要用到popupwindow,一时竟想不起来怎么用,赶紧上网查了查,自己写了个demo,并在此记录一下popupwindow的用法。
使用场景
popupwindow,顾名思义,就是弹窗,在很多场景下都可以见到它。例如actionbar/toolbar的选项弹窗,一组选项的容器,或者列表等集合的窗口等等。
基本用法
使用popupwindow很简单,可以总结为三个步骤:
- 创建popupwindow对象实例;
- 设置背景、注册事件监听器和添加动画;
- 显示popupwindow。
其中,第二步是可选的(不过基本上都要进行第二步的设置)。下面是一个简单的例子:
// 用于popupwindow的view view contentview=layoutinflater.from(context).inflate(layoutres, null, false); // 创建popupwindow对象,其中: // 第一个参数是用于popupwindow中的view,第二个参数是popupwindow的宽度, // 第三个参数是popupwindow的高度,第四个参数指定popupwindow能否获得焦点 popupwindow window=new popupwindow(contentview, 100, 100, true); // 设置popupwindow的背景 window.setbackgrounddrawable(new colordrawable(color.transparent)); // 设置popupwindow是否能响应外部点击事件 window.setoutsidetouchable(true); // 设置popupwindow是否能响应点击事件 window.settouchable(true); // 显示popupwindow,其中: // 第一个参数是popupwindow的锚点,第二和第三个参数分别是popupwindow相对锚点的x、y偏移 window.showasdropdown(anchor, xoff, yoff); // 或者也可以调用此方法显示popupwindow,其中: // 第一个参数是popupwindow的父view,第二个参数是popupwindow相对父view的位置, // 第三和第四个参数分别是popupwindow相对父view的x、y偏移 // window.showatlocation(parent, gravity, x, y);
每个方法的作用都写在注解里了,相信大家都能看懂。不过这里要注意这两行:
window.setbackgrounddrawable(new colordrawable(color.transparent)); window.setoutsidetouchable(true);
只有同时设置popupwindow的背景和可以响应外部点击事件,它才能“真正”响应外部点击事件。也就是说,当你点击popupwindow的外部或者按下“back”键时,popupwindow才会消失。
使用showasdropdown方法显示popupwindow
通常情况下,调用showasdropdown方法后popupwindow将会在锚点的左下方显示(drop down)。但是,有时想让popupwindow在锚点的上方显示,或者在锚点的中间位置显示,此时就需要用到showasdropdown方法的xoff和yoff参数了。
这里我们的目的不仅包括上面提到的两种情况(锚点上方或锚点中部),而是囊括了水平和垂直方向各5种显示方式:
水平方向:
align_left:在锚点内部的左边;
align_right:在锚点内部的右边;
center_hori:在锚点水平中部;
to_right:在锚点外部的右边;
to_left:在锚点外部的左边。
垂直方向:
align_above:在锚点内部的上方;
align_bottom:在锚点内部的下方;
center_vert:在锚点垂直中部;
to_bottom:在锚点外部的下方;
to_above:在锚点外部的上方。
下面来看张图:
我们先定义一个类对popupwindow进行简单的封装:
public abstract class commonpopupwindow { protected context context; protected view contentview; protected popupwindow minstance; public commonpopupwindow(context c, int layoutres, int w, int h) { context=c; contentview=layoutinflater.from(c).inflate(layoutres, null, false); initview(); initevent(); minstance=new popupwindow(contentview, w, h, true); initwindow(); } public view getcontentview() { return contentview; } public popupwindow getpopupwindow() { return minstance; } protected abstract void initview(); protected abstract void initevent(); protected void initwindow() { minstance.setbackgrounddrawable(new colordrawable(color.transparent)); minstance.setoutsidetouchable(true); minstance.settouchable(true); } public void showbashofanchor(view anchor, layoutgravity layoutgravity, int xmerge, int ymerge) { int[] offset=layoutgravity.getoffset(anchor, minstance); minstance.showasdropdown(anchor, offset[0]+xmerge, offset[1]+ymerge); } public void showasdropdown(view anchor, int xoff, int yoff) { minstance.showasdropdown(anchor, xoff, yoff); } public void showatlocation(view parent, int gravity, int x, int y) { minstance.showatlocation(parent, gravity, x, y); } }
这里我们要实现的就是“showbashofanchor”方法,其中有一个“layoutgravity”类型的参数,这就是控制popupwindow相对锚点位置的对象。下面来定义“layoutgravity”:
public static class layoutgravity { private int layoutgravity; // waring, don't change the order of these constants! public static final int align_left=0x1; public static final int align_above=0x2; public static final int align_right=0x4; public static final int align_bottom=0x8; public static final int to_left=0x10; public static final int to_above=0x20; public static final int to_right=0x40; public static final int to_bottom=0x80; public static final int center_hori=0x100; public static final int center_vert=0x200; public layoutgravity(int gravity) { layoutgravity=gravity; } public int getlayoutgravity() { return layoutgravity; } public void setlayoutgravity(int gravity) { layoutgravity=gravity; } public void sethorigravity(int gravity) { layoutgravity&=(0x2+0x8+0x20+0x80+0x200); layoutgravity|=gravity; } public void setvertgravity(int gravity) { layoutgravity&=(0x1+0x4+0x10+0x40+0x100); layoutgravity|=gravity; } public boolean isparamfit(int param) { return (layoutgravity & param) > 0; } public int gethoriparam() { for(int i=0x1; i<=0x100; i=i<<2) if(isparamfit(i)) return i; return align_left; } public int getvertparam() { for(int i=0x2; i<=0x200; i=i<<2) if(isparamfit(i)) return i; return to_bottom; } public int[] getoffset(view anchor, popupwindow window) { int anchwidth=anchor.getwidth(); int anchheight=anchor.getheight(); int winwidth=window.getwidth(); int winheight=window.getheight(); view view=window.getcontentview(); if(winwidth<=0) winwidth=view.getwidth(); if(winheight<=0) winheight=view.getheight(); int xoff=0; int yoff=0; switch (gethoriparam()) { case align_left: xoff=0; break; case align_right: xoff=anchwidth-winwidth; break; case to_left: xoff=-winwidth; break; case to_right: xoff=anchwidth; break; case center_hori: xoff=(anchwidth-winwidth)/2; break; default:break; } switch (getvertparam()) { case align_above: yoff=-anchheight; break; case align_bottom: yoff=-winheight; break; case to_above: yoff=-anchheight-winheight; break; case to_bottom: yoff=0; break; case center_vert: yoff=(-winheight-anchheight)/2; break; default:break; } return new int[]{ xoff, yoff }; } }
这里的主要方法就是“getoffset”,它会根据水平和垂直方向的gravity决定popupwindow相对锚点的位置。
使用“layoutgravity”时,可以通过“sethorigravity”和“setvertgravity”方法设置水平和垂直方向的gravity,或者新建一个“layoutgravity”对象。
下面是一个demo:
使用setanimationstyle方法添加动画
上面我们提到了为popupwindow设置背景和注册事件监听器,现在我们再来为popupwindow添加动画。
这里的动画是指popupwindow出现和消失时的动画。默认是直接弹出和消失,这样难免让用户有一种突兀的感觉;如果popupwindow能够“滑入”屏幕和“滑出”屏幕(或者其他方式),用户体验会更好。
为popupwindow添加动画可以调用`setanimationstyle`方法,该方法只有一个参数,就是指定动画的样式,因此我们需要定义动画资源和样式资源。
下面是一个“滑入滑出”动画:
<!-- res/anim/translate_in.xml --> <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromxdelta="0" android:toxdelta="0" android:fromydelta="100%" android:toydelta="0" android:duration="200" > </translate> </set>
<!-- res/anim/translate_out.xml --> <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromxdelta="0" android:toxdelta="0" android:fromydelta="0" android:toydelta="100%" android:duration="200" > </translate> </set>
然后定义“滑动”动画样式:
<!-- res/values/styles.xml --> <style name="animtranslate"> <item name="android:windowenteranimation">@anim/translate_in</item> <item name="android:windowexitanimation">@anim/translate_out</item> </style>
现在我们就可以为popupwindow添加“滑动”动画了:
window.setanimationstyle(r.style.animtranslate);
我们来看下效果:
ps:这里由于动画的时间太短(200ms),另外转gif的时候可能截取的频率有点低,导致滑动效果不是很明显,建议自己运行demo查看
现在popupwindow的出现/消失已经不是那么突兀了。不过,当弹窗出现后,发现弹窗和背景不是很容易区分,如果此时弹窗的背景能“变暗”就好了。
没问题,我们可以在弹窗出现后让背景变暗,并在弹窗消失后让背景还原:
window.setondismisslistener(new popupwindow.ondismisslistener() { @override public void ondismiss() { windowmanager.layoutparams lp=getwindow().getattributes(); lp.alpha=1.0f; getwindow().clearflags(windowmanager.layoutparams.flag_dim_behind); getwindow().setattributes(lp); } }); window.showatlocation(activitypopup, gravity.bottom, 0, 0); windowmanager.layoutparams lp=getwindow().getattributes(); lp.alpha=0.3f; getwindow().addflags(windowmanager.layoutparams.flag_dim_behind); getwindow().setattributes(lp);
现在再来看下效果:
现在popupwindow就比较明显了。
另外,我们还实现了透明度、缩放和旋转三种动画样式,实现方式和上述大同小异,这里就不再赘述。
源代码
上述所有代码(包括未给出的)都已上传到github:
https://github.com/jzyhywxz/popupwindow
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。