android实现筛选菜单效果
前言
由于android m的popupwindow与之前版本不一致,笔者找不到能够代码监听物理返回键的方式,故另寻方式实现筛选菜单。5.0及之前的版本可用popupwindow实现,详情请参考。
本篇采用dialog实现。
实现步骤
1、设置主题
一般设置如下
<style name="translucent_notitle" parent="android:style/theme.dialog"> <item name="android:windownotitle">true</item> <item name="android:background">#00000000</item> <item name="android:windowbackground">@android:color/transparent</item> <item name="android:windowanimationstyle">@null</item> <item name="android:windowisfloating">true</item> <item name="android:colorbackgroundcachehint">@null</item> <item name="android:windowistranslucent">true</item> <item name="android:backgrounddimenabled">false</item><span style="white-space:pre"> </span>背景暗淡效果 </style>
也可使用android.r.style.theme_panel和android.r.style.theme_light_panel。android.r.style.theme_panel代码如下,其与上面是一样的。
<style name="theme.panel"> <item name="windowbackground">@color/transparent</item> <item name="colorbackgroundcachehint">@null</item> <item name="windowframe">@null</item> <item name="windowcontentoverlay">@null</item> <item name="windowanimationstyle">@null</item> <item name="windowisfloating">true</item> <item name="backgrounddimenabled">false</item> <item name="windowistranslucent">true</item> <item name="windownotitle">true</item> </style>
2、设置内容的宽高
我们通过windowmanager.layoutparams实现。
windowmanager.layoutparams layoutparams = getwindow().getattributes(); layoutparams.width = screenwidth; layoutparams.height = contentheight; layoutparams.gravity = gravity.top; layoutparams.flags |= windowmanager.layoutparams.flag_not_touch_modal; //不阻塞事件传递到后面的窗口 getwindow().setattributes(layoutparams);
这里,设置layoutparams.flags |= windowmanager.layoutparams.flag_not_touch_modal; 则后面窗口的按钮可响应触摸事件(例,horizontalscrollview能横向滚动)。
3、设置动画
通过valueanimator实现。
enter = valueanimator.offloat(0, 1f).setduration(350); enter.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { dialogcontent.settranslationy((1 - animation.getanimatedfraction()) * -contentheight); } }); out = valueanimator.offloat(0, 1f).setduration(350); out.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { dialogcontent.settranslationy(animation.getanimatedfraction() * -contentheight); } }); out.addlistener(new animator.animatorlistener() { @override public void onanimationstart(animator animation) { } @override public void onanimationend(animator animation) { dismiss(); } @override public void onanimationcancel(animator animation) { } @override public void onanimationrepeat(animator animation) { } });
上面enter和out进行一系列设置,对out动画加开始结束监听。enter的start()方法在onstart()中调用
@override protected void onstart() { super.onstart(); dialogcontent.post(new runnable() { @override public void run() { enter.start(); } }); }
通过view的post方式,enter.start()会在view hierarchy(view树)构建完后执行(即视图构建完后执行)。view.post源码:
public boolean post(runnable action) { final attachinfo attachinfo = mattachinfo; if (attachinfo != null) { return attachinfo.mhandler.post(action); } // assume that post will succeed later viewrootimpl.getrunqueue().post(action); return true; }
第七行为关键代码,viewrootimpl为视图层级的顶部,实现了view和windowmanager之间的必要协议。runqueue:运行队列用来排入没有handler关联的view的以后工作。
所以这里dialog的视图显示时会调用enter.start()方法.
监听返回键:
@override public boolean onkeydown(int keycode, keyevent event) { if (keycode == keyevent.keycode_back) { out.start(); return true; } return super.onkeydown(keycode, event); }
out动画执行完后,onanimationend中调用dismiss()方法。
4、在点击的view下显示出来
public void showasdropview(view view) { windowmanager.layoutparams lp = getwindow().getattributes(); lp.width = screenwidth; int[] location = new int[2]; view.getlocationonscreen(location); // view.getlocationinwindow(location);<span style="white-space:pre"> </span>这里跟上面一句的效果一样,不知有什么区别 lp.y = location[1]-phoneconstant.statusheight+view.getheight(); lp.gravity = gravity.top; getwindow().setattributes(lp); contenttop = location[1]; show(); }
phoneconstant.statusheight为状态栏的高度,其通过反射获取
//反射获取状态栏高度 class<?> c = null; object obj = null; field field = null; int x = 0, sbar = 0; try { c = class.forname("com.android.internal.r$dimen"); obj = c.newinstance(); field = c.getfield("status_bar_height"); x = integer.parseint(field.get(obj).tostring()); phoneconstant.statusheight = getresources().getdimensionpixelsize(x); } catch(exception e1) { e1.printstacktrace(); }
也可通过以下方式获取
rect outrect = new rect(); activity.getwindow().getdecorview().getwindowvisibledisplayframe(outrect);
不过直接放在activity的oncreate中无效,只有界面绘制出来了才能获取到,可通过view.post()方式获取。
效果图:
另外,继承自alertdialog的自定义dialog点击edittext不弹出软键盘,所以一般继承自dialog。
控制对话框输入法的弹出,调用
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。