android.app.Dialog(23)里window的那些事(坑)
不要使用theme去配置Dialog的gravity
因为如今手机的尺寸比較大(相对于智能机開始的3.5in、4.0in),而Dialog默认都是显示在屏幕中心的位置,用户触摸起来多不便。
所以大多数产品都会要求Dialog在底部显示。
所以你可能这样写:
<style name="BottomDialog" parent="@android:style/Theme.Dialog">
<item name="android:gravity">bottom</item>
</style>
或者这样写:
dialog.getWindow().setGravity(Gravity.BOTTOM);
那么哪一种会更好一点呢?心里想,既然xml能够实现,那就用xml吧。毕竟xml有更好的配置性和维护性。
假设你真这样想的话,等你实践一下,就会发现。通过xml的方式配置Dialog的gravity。根本行不用。反而是另外一种是可行的。
这不科学啊,可是你冷静一下,去细致看一下Dialog的构造方法。原因并不复杂,你在style里配置的gravity属性,是没实用。都会被w.setGravity(Gravity.CENTER)所覆盖。
对这样的实现方法,不发表评论,理解并记住就好。
//Dialog.java
public Dialog(@NonNull Context context) {
this(context, 0, true);
}
public Dialog(@NonNull Context context, @StyleRes int themeResId) {
this(context, themeResId, true);
}
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
if (createContextThemeWrapper) {
if (themeResId == 0) {
final TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
themeResId = outValue.resourceId;
}
mContext = new ContextThemeWrapper(context, themeResId);
} else {
mContext = context;
}
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Window w = new PhoneWindow(mContext);
mWindow = w;
w.setCallback(this);
w.setOnWindowDismissedCallback(this);
w.setWindowManager(mWindowManager, null, null);
w.setGravity(Gravity.CENTER);
mListenersHandler = new ListenersHandler(this);
}
须要调用setAttributes。而不是仅改变attributes
问题来了,假设在上一个问题中。
我不用这种方法
dialog.getWindow().setGravity(Gravity.BOTTOM);
而改用
WindowManager.LayoutParams attributes = dialog.getWindow().getAttributes();
attributes.gravity = Gravity.BOTTOM;
//因为attributes是引用类型,所以不须要重写设置一遍。就能够改变它的值
//dialog.getWindow().setAttributes(attributes);
假设你也是这么想的,而且也这么做了,实际情况就是:它也行不用。可是你加上了setAttributes这种方法。就是好了。就在我不困惑不解的时候,我看下了setAttributes和setGravity的源代码,我发现他们都不约而同地调用dispatchWindowAttributesChanged这种方法。
奥。真相大白:原来改变了attributes的里面的值,还要通知Window进行回调一下。
//Window.java
public void setAttributes(WindowManager.LayoutParams a) {
mWindowAttributes.copyFrom(a);
dispatchWindowAttributesChanged(mWindowAttributes);
}
protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
if (mCallback != null) {
mCallback.onWindowAttributesChanged(attrs);
}
}
反思:还是要尽量,直接使用系统提供的公开方法。这样会避免入坑。
setAttributes要在setContentView之前调用
这时候我们想要设置这个dialog充满屏幕的宽(也同是须要调用setBackgroundDrawableResource来设置Dialog的DecorView背景透明,而且没有边框)。能够參考例如以下代码来完毕。
乍一看。没有什么问题,可是当你执行一下。它也行不通
Dialog dialog = new Dialog(this, android.R.style.Theme_Dialog);
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
dialog.setContentView(R.layout.dialog);
dialog.show();
而须要把dialog.setContentView(R.layout.dialog);放在设置Window的前面才行。
Dialog dialog = new Dialog(this, android.R.style.Theme_Dialog);
dialog.setContentView(R.layout.dialog);
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
dialog.show();
当我们读一下PhoneWindow的setContentView的源代码,再结合一下onWindowAttributesChanged方法。
就会恍然大悟,原来是这样。
哪样尼?就是回调onWindowAttributesChanged的时候。而mDecor根本没有创建出来,任意就直接return掉了。
//PhoneWindow.java
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
//Dialog.java
public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
if (mDecor != null) {
mWindowManager.updateViewLayout(mDecor, params);
}
}
最后:奇怪真是奇怪。眼下仅仅有setLayout有这个问题,而setBackgroundDrawableResource和setDimAmount都没有这个问题。
欢迎在以下留言。告知一下。
谢谢。
android.app.Dialog(23)里window的那些事(坑)的更多相关文章
- Android自定义Dialog
Android开发过程中,常常会遇到一些需求场景——在界面上弹出一个弹框,对用户进行提醒并让用户进行某些选择性的操作, 如退出登录时的弹窗,让用户选择“退出”还是“取消”等操作. Android系统提 ...
- Android Studio:Unable to add window android.view.ViewRootImpl$W@5e2d85a -- permission denied for this window 第一行代码
学习<第一行代码>的时候,出现的错误. java.lang.RuntimeException: Unable to start receiver com.example.sevenun.l ...
- Android PopupWindow Dialog 关于 is your activity running 崩溃详解
Android PopupWindow Dialog 关于 is your activity running 崩溃详解 [TOC] 起因 对于 PopupWindow Dialog 需要 Activi ...
- android.app.Activity 的介绍
发现当前Android的资料不是非常多,并且对于Activity的介绍也非常少.所以把官方文档的android.app.Activity的介绍翻译了一下,增加了一些自己的理解.各位假设认为我自己理解的 ...
- 探讨:你真的会用Android的Dialog吗?
一个Bug前几日出现这样一个Bug是一个RuntimeException,详细信息是这样子的: 复制代码代码如下: java.lang.IllegalArgumentException: View n ...
- Android 自定义Dialog类,并在Activity中实现按钮监听。
实际开发中,经常会用到Dialog,比如退出时候会弹出是否退出,或者还有一些编辑框也会用Dialog实现,效果图如下: 开发中遇到的问题无非在于如果在Activity中监听这个Dialog中实现的 ...
- android之dialog
先编写activity_main.xml文件 代码如下: <LinearLayout xmlns:android="http://schemas.android.com/apk/res ...
- Android之Dialog详解
Android中的对话框形式大致可分为五种:分别是一般对话框形式,列表对话框形式,单选按钮对话框,多选按钮对话框,自定义对话框. 在实际开发中,用系统的对话框会很少,因为太丑了,美工不愿意,多是使用自 ...
- Android中Dialog的使用
上一篇博文讲到对话框popWindow的使用,这篇博文主要解说Dialog的使用. 1.什么是Dialog? Dialog就是对话框的一种方式! 在Android开发中.我们常常会须要在Android ...
随机推荐
- shell-手机屏幕录制
今天在做android联系的时候,想要把自己写的demo效果记录下来.在网上发现了录制手机屏幕的方法,如下 adb shell screenrecord /sdcard/demo.mp4 解释 adb ...
- [NowCoder]牛客OI周赛3
A.地斗主 题意:\(4\times N\) 的地板,在上面铺 \(1\times 2\) 和 \(2\times 1\) 的地砖,求铺满方案数, \(N\le 10^9\) 原题..先把一列的状态压 ...
- js配合My97datepicker给日期添加天数
<input name="ctl00$ContentPlaceHolder1$txtTimeStart" type="text" value=" ...
- ReactJs 入门DEMO(转自别人)
附件是分享的一些他人的ReactJs入门DEMO,以前版本使用的是JSXTransformer.js,新版的用browser.min.js替代了. DEMO 下载地址:http://files.cnb ...
- 一个发邮件的demo 用golang
一个比较成熟的第三方包用来发邮件,可以带图片 和附件,项目地址 : github.com/go-gomail/gomail 一个发邮件的demo 用golang 文件目录树: -d:\test\goe ...
- Trie&可持久化Trie
WARNING:以下代码未经测试,若发现错误,欢迎指出qwq~ Trie树(字典树) 一种简单的数据结构,可存储大量字符串,可在$O(len)$的时间内完成插入,删除,查找等操作. 下面是一个简单的例 ...
- CentOS不能进入登录界面
http://blog.csdn.net/powerzone/article/details/6798646
- Moodle 中文 API 之 文件管理API
File API 文件管理 文件夹 1. 概述 2. 文件域 2.1 命名文件域 3. 提供文件给用户 4. 从用户那获取文件 5. 样例 5.1 浏览文件 5.2 移动文件 5.3 文件列表 5. ...
- 1.一个WEB应用的开发流程
先说项目开发过程中团队人员的分工协作. 一.人员安排 毕业至今的大部分项目都是独立完成,虽然也有和其他同事协作的时候,但自认为对团队协作的了解和认知都还有所欠缺.很清楚团队协作的重要性,但尚未有很好的 ...
- mysql 获取自增id的值的方法
原生jdbc方式: Statement.getGeneratedKeys() 示例: Statement stmt = null; ResultSet rs = null; try { // // C ...