android实现筛选菜单效果
前言
由于android M的popupwindow与之前版本不一致,笔者找不到能够代码监听物理返回键的方式,故另寻方式实现筛选菜单。5.0及之前的版本可用popupwindow实现,详情请参考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()会在viewhierarchy(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。
控制对话框输入法的弹出,调用
以上就是本文的全部内容,希望对大家的学习有所帮助。
- 一文读懂Python多线程
- 深入理解Python变量作用域与函数闭包
- TensorFlow从1到2 - 5 - 非专家莫入!TensorFlow实现CNN
- JetBrains Rider 破解 (ideaIU等等开发工具都通用)
- python中的小魔法(一)
- 由问题入手,步步爬出Python中赋值与拷贝的坑
- python爬取链家租房之获得每一页的房屋信息地址(持续更新)
- python使用正则表达式
- python在租房过程中的应用
- python爬虫反爬取---设置IP代理自动变换requests.get()中proxy的IP
- 【译】TensorFlow实现Batch Normalization
- 关于Python语言规范你需要知道的一些小tips
- R语言可视化——REmap(路径图)
- python面向对象
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- ubuntu中swap(虚拟内存)设置方法
- 详解Linux监控重要进程的实现方法
- CentOS环境下安装Redis3.0及phpredis扩展测试示例
- 使用Apache commons-cli包进行命令行参数解析的示例代码
- 详解如何在Ubuntu 16.04上增加Swap分区
- Mac本地文件上传到CentOS云服务器方法
- linux中把.c的文件编译成.so文件
- Ubuntu16.04 中 locate文件查找命令
- Ubuntu 16.04与Apache虚拟主机配置的步骤详解
- Linux删除目录下的文件的10种方法小结
- 利用Linux防火墙隔离本地欺骗地址的方法详解
- 视图在SQL中的作用是什么,它是怎样工作的?
- Linux命令行上如何使用日历详解
- 在Linux下修改和重置root密码的方法(超简单)
- 在Centos上搭建Maven中央仓库的方法