Android 7.0 PopupWindow 的兼容问题
Android7.0 PopupWindow的兼容问题
Android7.0
中对 PopupWindow
这个常用的控件又做了一些改动,修复了以前遗留的一些问题的同时貌似又引入了一些问题,本文通过在7.0设备上实测并且结合源码分析,带你了解关于 PopupWindow
的相关改动。
Android7.0
中下面两个问题解决了,这里强调一下,不是说从 Android7.0
开始才解决这两个问题的,因为具体版本细节没去深究。可能在其他的某些版本下面的问题也是被解决了的。
PopupWindow
不响应点击外部消失和返回键消失的解决方法,博文地址:
http://www.cnblogs.com/popfisher/p/5608717.html- 不得不吐槽的
Android PopupWindow
的几个痛点(实现带箭头的上下文菜单遇到的坑),博文地址:
http://www.cnblogs.com/popfisher/p/5944054.html
Android7.0 中又引入了新的问题(这就非常的尴尬了)
- 调用
update
方法,PopupWindow
的Gravity
会改变
从源码看7.0怎么解决遗留问题的
解决 PopupWindow
不响应点击外部消失和返回键消失的问题,我们是通过自己设置一个背景。Android7.0
中不设置背景也是可以的,那么它的代码肯定做了处理。从 api24
的源码中找到 PopupWindow.java
文件,我找到里面的 preparePopup
方法如下:
private void preparePopup(WindowManager.LayoutParams p) {
if (mContentView == null || mContext == null || mWindowManager == null) {
throw new IllegalStateException("You must specify a valid content view by "
+ "calling setContentView() before attempting to show the popup.");
}
// The old decor view may be transitioning out. Make sure it finishes
// and cleans up before we try to create another one.
if (mDecorView != null) {
mDecorView.cancelTransitions();
}
// When a background is available, we embed the content view within
// another view that owns the background drawable.
if (mBackground != null) {
mBackgroundView = createBackgroundView(mContentView);
mBackgroundView.setBackground(mBackground);
} else {
mBackgroundView = mContentView;
}
mDecorView = createDecorView(mBackgroundView);
// The background owner should be elevated so that it casts a shadow.
mBackgroundView.setElevation(mElevation);
// We may wrap that in another view, so we'll need to manually specify
// the surface insets.
p.setSurfaceInsets(mBackgroundView, true /*manual*/, true /*preservePrevious*/);
mPopupViewInitialLayoutDirectionInherited =
(mContentView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
}
重点只需要看 mDecorView = createDecorView(mBackgroundView);
可以看到不管 mBackground
变量是否为空,最终都执行了这句代码,这句代码会多加一层 ViewGroup
把 mBackgroundView
包进去了,里面应该包含了对返回键的处理逻辑,我们再看看 createDecorView
方法源码:
private PopupDecorView createDecorView(View contentView) {
final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
final int height;
if (layoutParams != null && layoutParams.height == WRAP_CONTENT) {
height = WRAP_CONTENT;
} else {
height = MATCH_PARENT;
}
final PopupDecorView decorView = new PopupDecorView(mContext);
decorView.addView(contentView, MATCH_PARENT, height);
decorView.setClipChildren(false);
decorView.setClipToPadding(false);
return decorView;
}
createDecorView
里面还是没有直接看出对事件的处理,但是里面有个 PopupDecorView
类,应该在里面了吧,继续看:
private class PopupDecorView extends FrameLayout {
//......有代码被省略
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
if (getKeyDispatcherState() == null) {
return super.dispatchKeyEvent(event);
}
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
final KeyEvent.DispatcherState state = getKeyDispatcherState();
if (state != null) {
state.startTracking(event, this);
}
return true;
} else if (event.getAction() == KeyEvent.ACTION_UP) {
final KeyEvent.DispatcherState state = getKeyDispatcherState();
if (state != null && state.isTracking(event) && !event.isCanceled()) {
dismiss();
return true;
}
}
return super.dispatchKeyEvent(event);
} else {
return super.dispatchKeyEvent(event);
}
}
//......有代码被省略
@Override
public boolean onTouchEvent(MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
if ((event.getAction() == MotionEvent.ACTION_DOWN)
&& ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) {
dismiss();
return true;
} else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
dismiss();
return true;
} else {
return super.onTouchEvent(event);
}
}
//......有代码被省略
}
从上面的代码中我们看到了KeyEvent.KEYCODE_BACK
和 MotionEvent.ACTION_OUTSIDE
,没错这里有对返回键和其他事件的处理。
至于怎么解决 showAsDropDown
方法弹出位置不对的问题,也就是上文中描述的第二个问题,本文就不贴源码了,感兴趣的可以下载源码去看看,本文只是提供一种解决问题的思路,希望大家能从源码中找到解决问题的办法,这才是作者希望达到的效果。 文章末尾会给出 Android7.0 PopupWindow.java
的 java 文件。
Android7.0引入的新问题
调用 update
方法时,PopupWindow
的 Gravity
会改变,导致位置发生了改变,具体看下图:
showAtLocation传入Gravity.Bottom:从屏幕底部对齐弹出
调用update方法更新第5点中弹出PopupWindow,发现PopupWindow的Gravity发生了改变
关于这个问题还有篇文章可以参考, http://www.jianshu.com/p/0df10893bf5b
Android7.0 PopupWindow其他改动点,与Android5.1的对比
主界面
1. PopupWindow高宽都设置为match_parent:7.0(左边)从屏幕左上角弹出,5.1(右边)从anchorView下方弹出
2. 宽度wrap_content-高度match_parent:7.0(左边)从屏幕左上角弹出,5.1(右边)从anchorView下方弹出
3. 宽度match_parent-高度wrap_content:都从anchorView下方弹出
4. 宽度wrap_content-高度大于anchorView到屏幕底部的距离:7.0与5.1都从anchorView上方弹出,与anchorView左对齐
源码地址
Github工程地址,收录了 PopupWindow
相关使用问题:
https://github.com/PopFisher/SmartPopupWindow
Android 7.0 PopupWindow.java 文件:
https://github.com/PopFisher/SmartPopupWindow/blob/master/sourcecode/PopupWindow(7.0).java
总结
Android PopupWindow
这个控件 Google
一直没有优化好,使用时需要参考我之前的几篇文章。本文是希望读者善于从源码的角度去分析和解决问题,加深自己对源码的理解,对问题的理解,这样印象要深刻一些。
本来2017年回来还没有时间写写文章,这篇文章也是巧合,同事在 Android7.0
中发现 PopupWindow
使用上有 bug
,所以我就借此机会研究一下,虽然知识点简单,但是也花费了几个小时的时间整理出这样一篇文章。如果读者觉得有用,别忘记点击推荐哦,总之也算是开了一个好头吧,以后还是会坚持每个月写些文章出来分享。
Android 7.0 PopupWindow 的兼容问题的更多相关文章
- Android 7.0 PopupWindow 又引入新的问题,Google工程师也不够仔细么
Android7.0 PopupWindow的兼容问题 Android7.0 中对 PopupWindow 这个常用的控件又做了一些改动,修复了以前遗留的一些问题的同时貌似又引入了一些问题,本文通 ...
- Android 7.0 因为file://引起的FileUriExposedException异常
最近作者又碰到因为android 7.0 引起的兼容问题了. 在7.0以前的版本: //创建临时图片 File photoOutputFile = SDPath.getFile("temp. ...
- 「国产系统」Tubian 0.3,兼容Windows和Android的GNU/Linux系统!
0.4版已发布:https://www.cnblogs.com/tubentubentu/p/16741197.html Sourceforge.net主页(提供下载):https://sourcef ...
- 「国产系统」Tubian 0.2,兼容Windows和Android的GNU/Linux系统!
0.3版已发布:https://www.cnblogs.com/tubentubentu/p/16733005.html Sourceforge.net主页(提供下载):https://sourcef ...
- 「国产系统」Tubian 0.1,兼容Windows和Android的GNU/Linux系统!
Tubian 0.42已发布:https://www.cnblogs.com/tubentubentu/p/16745926.html Tubian是我的自用系统整理而成的Linux发行版,基于Deb ...
- Android数据存储之Android 6.0运行时权限下文件存储的思考
前言: 在我们做App开发的过程中基本上都会用到文件存储,所以文件存储对于我们来说是相当熟悉了,不过自从Android 6.0发布之后,基于运行时权限机制访问外置sdcard是需要动态申请权限,所以以 ...
- Android 6.0 - 动态权限管理的解决方案
Android 6.0版本(Api 23)推出了很多新的特性, 大幅提升了用户体验, 同时也为程序员带来新的负担. 动态权限管理就是这样, 一方面让用户更加容易的控制自己的隐私, 一方面需要重新适配应 ...
- 【译】Android 6.0 Changes (机翻加轻微人工校对)
Android 6.0 Changes In this document Runtime Permissions Doze and App Standby Apache HTTP Client Rem ...
- Android中的PopupWindow
1.功能 PopupWindow这个类用来实现一个弹出框,可以使用任意布局的View作为其内容,这个弹出框是悬浮在当前activity之上的,可以设置显示位置. 2.需求 弹出软键盘,实现键盘功能从而 ...
随机推荐
- IOS开发-OC学习-Foundation框架练习
OC语言Foundation框架中字典.字符串.数组的应用: NSString *string = @"China|Usa|France"; NSArray *array = [s ...
- My first essay
今天是我开通博客第一天,从此开始了我的博客之路.为了实现成为程序猿的我,现在开始努力啦~今年大三,就读杭州电子科技大学,通信工程专业.现在在自学web前端,虽然与我就读专业并无多大相关,但是这是根据自 ...
- iOS 界面布局,设置约束
1. 设置控件的宽度是父视图的宽度的1/2 在控件上按住ctrl,按住鼠标左键,拖动到父视图,这时出来一个选项,选中aspect 在Multiplier中填上1:2 即可,其它的比例也是这样 2. 设 ...
- 如何在Eclipse下安装myeclipse插件
来自http://www.blogjava.net/show911/archive/2008/04/27/86284.html 下载myeclipse插件 支持eclipse3.1.x, 具体安装步骤 ...
- PHP常用函数(收集)
<?php //===============================时间日期=============================== //y返回年最后两位,Y年四位数,m月份数字 ...
- div+CSS实现段落首行缩进两个字符
段落前面空两个字的距离,不要再使用空格了,用CSS实现段落首缩进两个字符.应该使用首行缩进text-indent.text-indent可以使得容器内首行缩进一定单位.比如中文段落一般每段前空两个汉字 ...
- Angular - - ngApp、ngBind、ngBindHtml、ngNonBindable
对于ng-系列的指令,每篇文章写2-5个吧,不然显得文章好短.... ngApp 使用这个指令自动启动一个AngularJS应用.ngApp指令指定了应用程序的根节点,通常会将ngApp放置在网页的根 ...
- 2.13.3:获取请求模板(Core Data 应用程序实践指南)
可以不用手动写谓词,用Xcode的Data Model Designer.只是要用到AND .OR等逻辑组合时,还得用代码写谓词. 程序示例操作如下: 选中Model.xcdatamodeld 点击E ...
- endnote X7使用方法
网页版的endnote不能添加新模版,只能用模版库里的那些,所以转而试试离线版客户端. 1.下载安装完以后(下载地址就不给了,网上有很多),在word里可以看到顶栏有插件,如果你同时也安装了在线版本, ...
- HDU-1864-最大报销额
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1864 这题开始题意没搞清楚,就做题了,导致浪费了很多的时间,不应该啊, 注意事项:每张发票上,单项物品 ...