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="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style
     * and Theme Resources</a> for more information about defining and using
     * styles.  This theme is applied on top of the current theme in
     * <var>context</var>.  If 0, the default dialog theme will be used.
     */
    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.结论见开篇,不再赘述

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

时间: 2024-10-12 08:10:52

Dialog和软键盘在屏幕上的并存问题:的相关文章

Android 软键盘控制方法、以及开发中遇到的一些问题。

Android 提供了 windowSoftInputMode 属性来控制输入法软键盘窗口和 Activity 主窗口的交互,分为 窗口尺寸调整系列 和 输入法软键盘显示控制系列. 窗口尺寸调整系列: 该系列参数用来控制当软键盘弹起时,Activity 主窗口的调整策略,因为如果不调整主窗口,很可能会导致当前输入的控件被软键盘遮挡. adjustPan: Activity的主窗口并不会重新调整大小来为输入法腾出空间,而是窗口的内容会自动上下晃动来保证当前获得焦点的控件不会被键盘遮挡住,然后用户可

360浏览器文本框获得焦点后被软键盘遮罩的问题

场景是这样的,站点上筛选按钮点击后弹出层(fixed),当输入框获取焦点以后弹出系统自带的软键盘,在android上十款浏览器挨个测试比对,发现在360浏览器弹出键盘以后获取焦点的文本框被软键盘覆盖了.截图如下                      (未获取软键盘焦点的情况)               (chrome浏览器调起软键盘的情况)            (360浏览器调起软键盘情况) 那么问题来了,浏览器的软键盘显示出来又哪几种情况呢?英文  中文(网上找的) 经过简单的了解,大

安卓移动端软键盘弹出问题解决方案

移动端开发难免拿到输入框居中或者位于底部的情况,ios 端,软键盘能够按正常预期向上滑动(这里有个问题,当 input 聚焦时,弹出软键盘,input 上滑,此时屏幕是具有滚动效果的,还没找到合适的解决方案),Android 端,并不会滑动,通常做法是设置 window.scrollTo(0, virtualKeyboard.Height), 但是如果你的 input 所在的 div 是绝对定位的话,window.scrollTo 这个事件是监听不到的,这里给出另一套解决方案 self.refs

Android软键盘基础总结(一)

一年多时间以来,一直在学习,去从来疏于整理,搞得知识点好凌乱,是时候开始做个总结啦,一步步来,从基础深入吧. 今天就讲解Android的软键盘windowSoftInputMode属性:其中有adjustXX共5个合stateXX共6个:加起来就是10个: adjustXX这一系列的属性在测试中发现是通过调整窗体/窗体里面的某些属性来显示软件盘的.注意:这一系列模式只在 有输入必要的时候才会弹出软键盘 adjustResize:activity总是会被调整大小,来确保软键盘可以显示出来,并且不一

004-实现点击任意屏幕上非文本框点移除键盘

实现点击任意屏幕上非文本框点移除键盘 我们在开发的过程中若要实现此功能只要将下面这些代码拷贝到你要实现的项目里面就可以实现此功能. 代码如下: - (void)viewDidLoad { [super viewDidLoad]; [self setUpForDismissKeyboard]; } - (void)setUpForDismissKeyboard { NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; UI

汇编一点点提高3——键盘输入8位二进制数,存入NUM单元,并在屏幕上显示对应的16进制数

此程序要注意一下几点: 1.dos1号功能--带回显的键盘输入,自动存入al 2.dos7号功能--不带回显的键盘输入,自动存入al,若要在屏幕中显示要调用DOS2号功能 3.将输入的多个二进制数转换为ASCII码 input:  mov ah,1  int 21h  add bl,bl  cmp al,'1'  jnz P1  inc bl  P1: dec ch  jnz input 4.换行子程序: newline: mov ah,2 mov dl,13 int 21h mov ah,2

ios上有时候提交按钮点击两次才可以取消输入框软键盘

ios上有时候提交按钮点击两次才可以取消输入框软键盘,点击第一次软键盘消失,点击第二次输入框页面消失,这样用户体验不好.我的做法是用 touchstart 代替click来处理 反应快,但是有时候会出现 输入框消失后 软键盘又弹出来了,得手动关闭软键盘才可以,这个时候给输入框一个主动取消焦点的事件就可以解决 $("..").blur();

点击屏幕其他地方让软键盘消失

/* 在获取不到焦点的时候隐藏软键盘 */ @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub if (event.getAction() == MotionEvent.ACTION_DOWN) { if (getCurrentFocus() != null && getCurrentFocus().getWindowToken() != null) {

解决安卓手机上软键盘弹出挤压背景的问题

demo: // 解决本页面软键盘弹窗背景挤压的问题 var clientHeight = document.documentElement.clientHeight || document.body.clientHeight; $(window).on('resize', function () { var nowClientHeight = document.documentElement.clientHeight || document.body.clientHeight; if (cli