欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

android实现筛选菜单效果

程序员文章站 2022-06-20 14:45:33
前言 由于android m的popupwindow与之前版本不一致,笔者找不到能够代码监听物理返回键的方式,故另寻方式实现筛选菜单。5.0及之前的版本可用popupwindow...

前言

由于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()方式获取。

效果图:

android实现筛选菜单效果

另外,继承自alertdialog的自定义dialog点击edittext不弹出软键盘,所以一般继承自dialog。

控制对话框输入法的弹出,调用


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。