Dialog和软键盘在屏幕上的并存问题:

最近在优化项目登陆模块的用户体验,验证码登陆的时候出现了这个问题,当弹出加载框的时候自动把之前打开的软键盘给隐藏掉了,感觉用户体验不太好。在网上也搜不到针对这个问题的解答,最后还是想看看源码中有没有什么蛛丝马迹,果然还是通过源码解决了这个问题,不得感叹一下:关键时刻还是源码好使啊!

首先说下结论:
1.AlertDialog和ProgressDialog默认可以和系统软键盘并存与同意屏幕(其实质是并存于同一个window窗口,具体下面会解释)
2.Dialog以及用户自定义的继承自Dialog的弹出框默认不可以和软键盘并存与同一屏幕
如果Dialog对象或者自定义弹出框想要和软键盘共存与同一屏幕,可以进行如下设置:
2.1Dialog对象设置

Dialog di = new Dialog(MainActivity.this);
    di.setTitle("test   test");
    di.getWindow().setFlags(
            WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
            WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);

2.2自定义继承自Dialog对象的设置

public class LoadingDialog extends Dialog {
                            ...
        }
    loadDialog = new LoadingDialog(this, R.style.dialog);
    loadDialog.getWindow().setFlags(
            WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
            WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);

结论分析:
解析思路预览:
1. Activity是什么?Dialog是什么?软键盘的实质是什么?他们三个和Window窗口的关系是什么?
2. Dialog和软键盘的关系是什么?
3. 是谁控制Dialog和软键盘的显示的?怎么控制?
4. 得出结论:如何让Dialog和软键盘并存?


  1. 1.1先从我们最熟悉的Activity说起:
    源码中Acitvity的部分注释如下:
/**
 * An activity is a single, focused thing that the user can do.  Almost all
 * activities interact with the user, so the Activity class takes care of
 * creating a window for you in which you can place your UI with
 * {@link #setContentView}.  While activities are often presented to the user
 * as full-screen windows, they can also be used in other ways: as floating
 * windows (via a theme with {@link android.R.attr#windowIsFloating} set)
 * or embedded inside of another activity (using {@link ActivityGroup}).
 *......
 */
 public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2 {...}

从中得知:Acitvity的布局是添加在所创建的window窗口中的。

1.2这段注释说的很明白,如果我们想要把dialog放在界面中软键盘的上面显示,就需要给当前的window设置FLAG_ALT_FOCUSABLE_IM这个属性。

/** <p>Often you will want to have a Dialog display on top of the current
 * input method, because there is no reason for it to accept text.  You can
 * do this by setting the {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM
 * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} window flag (assuming
 * your Dialog takes input focus, as it the default) with the following code:
 */
 public class Dialog implements DialogInterface, Window.Callback,
        KeyEvent.Callback, OnCreateContextMenuListener {
        ...
            /**
     * Create a Dialog window that uses the default dialog frame style.
     * 
     * @param context The Context the Dialog is to run it.  In particular, it
     *                uses the window manager and theme in this context to
     *                present its UI.
     */
    public Dialog(Context context) {
        this(context, 0, true);
    }

    /**
     * Create a Dialog window that uses a custom dialog style.
     * 
     * @param context The Context in which the Dialog should run. In particular, it
     *                uses the window manager and theme from this context to
     *                present its UI.
     * @param theme A style resource describing the theme to use for the 
     * window. See <a href=#>
    public Dialog(Context context, int theme) {
        this(context, theme, true);
    }

    Dialog(Context context, int theme, boolean createContextWrapper) {
        if (theme == 0) {
            TypedValue outValue = new TypedValue();
            context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,
                    outValue, true);
            theme = outValue.resourceId;
        }

        mContext = createContextWrapper ? new ContextThemeWrapper(context, theme) : context;
        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        Window w = PolicyManager.makeNewWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);
        mListenersHandler = new ListenersHandler(this);
    }
        ...
         /**
     * Set the screen content to an explicit view.  This view is placed
     * directly into the screen's view hierarchy.  It can itself be a complex
     * view hierarhcy.
     * 
     * @param view The desired content to display.
     */
    public void setContentView(View view) {
        mWindow.setContentView(view);
    }
        ...
        }

通过源码中构造方法的注释“Create a Dialog window”,可以看出来,dialog需要创建一个属于自己的window窗口;
并且在它的构造方法中就初始化创建了这个window的对象:
Window w = PolicyManager.makeNewWindow(mContext);
mWindow = w;
之后把要加载的dialog的布局设置到window窗口上:
public void setContentView(View view) {
mWindow.setContentView(view);
}

从中得知:显示dialog是需要创建一个新的window窗口的。

1.3软键盘的实质就是一个自定义的Dialog,这里不再细说

1.4所以,activity和dialog都是依附于window窗口存在于手机界面上的,软键盘也是一个dialog。

2.要显示的dialog和软键盘是什么关系
由于软键盘也是一个自定义dialog,那么实质上就是我们的自定义dialog和软键盘的并存关系了。

3.由于dialog是依附于window窗口存在的,所以是由window的属性控制dialog和软键盘的显示。
dialog中源码注释已经说明如果需要dialog显示在软键盘之上,就需要为window添加FLAG_ALT_FOCUSABLE_IM这个属性。我们通过继承Dialog自定义的弹出窗口也需要为他们所在的window设置这个属性才可以和软键盘并存。
Dialog和软键盘并存分为两种情况:
一是,dialog布局中没有编辑框,dialog只是浮现在软键盘上面,实质是软件在下面acitivity所在的window中而dialog存在与自身所创建的window中,例如google给我们做的AlertDialog和ProgressDialog都是这样,这两个弹框默认都可以和软键盘并存并且浮现在软键盘之上的,因为这两个弹框默认添加到设置了该属性的window窗口的。
AlertDialog源码注释如下:

/** <p>The AlertDialog class takes care of automatically setting
 * {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM
 * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} for you based on whether
 * any views in the dialog return true from {@link View#onCheckIsTextEditor()
 * View.onCheckIsTextEditor()}.  Generally you want this set for a Dialog
 * without text editors, so that it will be placed on top of the current
 * input method UI.  You can modify this behavior by forcing the flag to your
 * desired mode after calling {@link #onCreate}.
 */
public class AlertDialog extends Dialog implements DialogInterface {...}

另外一种情况,dialog布局中有编辑框,需要使用软键盘进行文本编辑,我们自定义的继承自Dialog的弹框默认就可以实现在当前window中弹出软键盘。

4.结论见开篇,不再赘述

版权声明:本文为博主原创文章,未经博主允许不得转载。

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
我们项目的工具类中,这些方法应该是常驻方法,因为他们太常用了,一方面将这些方法总结在这篇文章中,以便于自己日后使用,另一方面也给大家提供个方便,省的每次到处去找了。 1.判断当前是否已经连网 不管连接的是WIFI还是移动网络,最终都会返回true,否则返回false public static boolean isNetworkAvailable (Context context){ if (context!= null ) { //获取系统服务 ConnectivityManager cm = (Con

GitBook 配置说明 - 2015-08-01 19:08:17

1. 下载并安装 npm node-v0.12.0.pkg http://nodejs.org/download/ 2. 安装 gitbook $ sudo npm install gitbook -cli -g 3. 进入终端 cd 到新建的电子书目录 $ touch SUMMARY .md $ gitbook init 4. 下载并安装 gitbookEditor,gitbook 本地编辑器 https://github.com/GitbookIO/editor/releases 打开并选择刚刚 in

浏览器中展示地图 - 2015-08-01 19:08:09

我们在APP中开发中经常会内嵌地图展示某一具体位置,比如用地图展示某一个具体位置。以上海徐家汇为例,如下图所示: 如果我们直接使用浏览器打开的话,参考 http://developer.baidu.com/map/uri-introweb.htm 如果我们已知经纬度(lat, lng),那么很方便,我们可以使用下面的方式来展示 Intent intent = new Intent();            intent .setAction( "android.intent.action.VIEW" )

蚁视头盔上手简评 - 2015-08-01 19:08:39

蚁视头盔简评   转载请注明出处:http://blog.csdn.net/yanzhanyi/article/details/46815321 蚁视头盔自去年上市以来似乎并没有太大的影响力,但像我这样对VR和AR这么着迷的用户,拿到一个领域内产品的试用机会还是很想玩一玩的。 一、外观 打开盒子,不同的部件被分在不同的格子里, 蚁视外观设计还算可以,眼镜的手感和材质还可以。上图照了几张外观,其中头盔两边接出来的两根线实在是不仅碍眼而且碍脸。我是应该把头套进去呢?还是让它耷拉下来呢……还有那两个正前方上面的

Swift之贪婪的UIButton - 2015-08-01 19:08:19

一、内容概要 按钮是所有UI体系中非常重要的组件,在iOS中按钮UIButton的使用也非常灵活,本文将从以下几点介绍UIButton的使用( 基于Swift2.0 ): 1.UIButton基础2.UIButton图片使用3.圆角按钮4.复选框按钮5.倒计时按钮(闪烁问题也轻松解决)6.贪婪按钮(父控件事件也归我,扩大事件响应区域) 二、UIButton基础 2.1创建 UIButton提供了一个简单的构造方法 convenience init(type buttonType: UIButtonType

高仿美团iOS版,版本号5.7 - 2015-08-01 19:08:01

高仿美团iOS版,版本号:5.7 github链接: https://github.com/lookingstars/meituan 如果你觉得不错,欢迎 star 哦 1.团购首页: 1.1  团购--》猜你喜欢-》右上角分享 到微信朋友圈,新浪微博等 2.商家 3.名店抢购 4.推荐: 5.热门排队 6.团购详情 7.上门服务 8.上门洗车 9.地图:附近美食 10.商家分类显示 11.启动页广告: 12.我的 13.更多: 版权声明:本文为博主原创文章,未经博主允许不得转载。
        我是一个工作3年多的android开发,由于公司和个人发展原因,打算跳槽!这次跳槽又给我好好的上了一课!所以我自己反思总结了一下,然后整理出一下几点 程序员打算跳槽的时候需要注意的几点! 一 先想好自己要去一家什么样的公司,对自己有一个清晰的规划目标。 因为这时候你已经有一定的选择权了,不是刚毕业出来找工作那会就希望很快上班了。所以你要想好想去一家什么样的公司, 一是对 投简历的时候你会有目的性的去投 不要投太多。我投简历投了差不多40家公司,基本接到最少30个电话。所以大部分面试都没有去
假设读者已经知道push的基本知识,本文只是解决一些适配,兼容问题。如果对push 不甚了解,参考下面的文章 1.【iOS push全方位解析】(一)  push的概述 2.【iOS push全方位解析】(二)  生成push证书,生成Provisioning Profile 3. 【iOS push全方位解析】(三) 一个极简的demo,并测试一下push 4. 给iOS程序添加push代码 ======================正文======================= 客户端需要处理三
先放上效果 惊现塞拉酱 算法是Weta Digital根据siggraph2003的论文加以改进,改进之前使用的是Kajiya and Kay’s 模型,它能量不守恒,也就是说不是基于物理的,不准确   电镜下真实头发丝纤维的照片,我们发现上面有很多重叠的角质层叫做毛小皮也叫毛鳞片,他们相对根部的倾斜角度大约为3°,近似模型如下图   头发纤维的模型 R为反射(reflection),T为穿透(transmission),也就是折射 这里假设光有三种传播方式R, TT, TRT R是直接反射, TT是经过两
Android基础入门教程——1.9 Android程序签名打包 标签(空格分隔): Android基础入门教程 本节引言: 第一章的倒数第二节,本节给大家介绍的是如何将我们的程序打包成Apk文件,并且为我们的Apk签名! 上一节中已经说了,我们后续的教程使用的IDE是Android Studio,所以本节讲解的也是AS(后面都这样 简称吧)下对项目进行打包签名! 1.什么是签名,有什么用: Android APP都需要我们用一个证书对应用进行数字签名,不然的话是无法安装到Android手机上的,平时我们