`

Android软键盘的隐藏显示研究[转]

 
阅读更多

 Android是一个针对触摸屏专门设计的操作系统,当点击编辑框,系统自动为用户弹出软键盘,以便用户进行输入。
    那么,弹出软键盘后必然会造成原有布局高度的减少,那么系统应该如何来处理布局的减少?我们能否在应用程序中进行自定义的控制?这些是本文要讨论的重点。

    一、软键盘显示的原理
    软件盘的本质是什么?软键盘其实是一个Dialog!
    InputMethodService为我们的输入法创建了一个Dialog,并且将该Dialog的Window的某些参数(如Gravity)进行了设置,使之能够在底部或者全屏显示。当我们点击输入框时,系统对活动主窗口进行调整,从而为输入法腾出相应的空间,然后将该Dialog显示在底部,或者全屏显示。
    二、活动主窗口调整
    android定义了一个属性,名字为windowSoftInputMode, 用它可以让程序可以控制活动主窗口调整的方式。我们可以在AndroidManifet.xml中对Activity进行设置。如:android:windowSoftInputMode="stateUnchanged|adjustPan"
    该属性可选的值有两部分,一部分为软键盘的状态控制,另一部分是活动主窗口的调整。前一部分本文不做讨论,请读者自行查阅android文档。
    模式一,压缩模式
    windowSoftInputMode的值如果设置为adjustResize,那么该Activity主窗口总是被调整大小以便留出软键盘的空间。
我们通过一段代码来测试一下,当我们设置了该属性后,弹出输入法时,系统做了什么。
    重写Layout布局:

  1. public class ResizeLayout extends LinearLayout{ 
  2.     private static int count = 0
  3.      
  4.     public ResizeLayout(Context context, AttributeSet attrs) { 
  5.         super(context, attrs); 
  6.     } 
  7.      
  8.     @Override 
  9.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {     
  10.         super.onSizeChanged(w, h, oldw, oldh); 
  11.          
  12.         Log.e("onSizeChanged " + count++, "=>onResize called! w="+w + ",h="+h+",oldw="+oldw+",oldh="+oldh); 
  13.     } 
  14.      
  15.     @Override 
  16.     protected void onLayout(boolean changed, int l, int t, int r, int b) { 
  17.         super.onLayout(changed, l, t, r, b); 
  18.         Log.e("onLayout " + count++, "=>OnLayout called! l=" + l + ", t=" + t + ",r=" + r + ",b="+b); 
  19.     } 
  20.      
  21.     @Override 
  22.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
  23.         super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
  24.          
  25.         Log.e("onMeasure " + count++, "=>onMeasure called! widthMeasureSpec=" + widthMeasureSpec + ", heightMeasureSpec=" + heightMeasureSpec); 
  26.     } 

    我们的布局设置为:

  1. <com.winuxxan.inputMethodTest.ResizeLayout  
  2.     xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:id="@+id/root_layout" 
  4.     android:layout_width="fill_parent" 
  5.     android:layout_height="fill_parent" 
  6.     android:orientation="vertical" 
  7.     > 
  8.      
  9.     <EditText 
  10.         android:layout_width="fill_parent"  
  11.         android:layout_height="wrap_content"  
  12.     /> 
  13.    
  14.     <LinearLayout 
  15.             android:id="@+id/bottom_layout" 
  16.             android:layout_width="fill_parent"  
  17.             android:layout_height="fill_parent"  
  18.             android:orientation="vertical" 
  19.             android:gravity="bottom">
  20.     
  21.     <TextView   
  22.         android:layout_width="fill_parent"  
  23.         android:layout_height="wrap_content"  
  24.         android:text="@string/hello" 
  25.         android:background="#77777777" 
  26.       /> 
  27.    </LinearLayout> 
  28. </com.winuxxan.inputMethodTest.ResizeLayout> 

    AndroidManifest.xml的Activity设置属性:android:windowSoftInputMode = "adjustResize"
    运行程序,点击文本框,查看调试信息:
    E/onMeasure 6(7960): =>onMeasure called! widthMeasureSpec=1073742144, heightMeasureSpec = 1073742024
    E/onMeasure 7(7960): =>onMeasure called! widthMeasureSpec=1073742144, heightMeasureSpec = 1073742025
    E/onSizeChanged 8(7960): =>onSizeChanged called! w=320,h=201,oldw=320,oldh=377
    E/onLayout 9(7960): =>OnLayout called! l=0, t=0,r=320,b=201
    从调试结果我们可以看出,当我们点击文本框后,根布局调用了onMeasure,onSizeChanged和onLayout。
    实际上,当设置为adjustResize后,软键盘弹出时,要对主窗口布局重新进行measure和layout,而在layout时,发现窗口的大小发生的变化,因此调用了onSizeChanged。
    从下图的运行结果我们也可以看出,原本在下方的TextView被顶到了输入法的上方。

    

    模式二,平移模式
    windowSoftInputMode的值如果设置为adjustPan,那么该Activity主窗口并不调整屏幕的大小以便留出软键盘的空间。相反,当前窗口的内容将自动移动以便当前焦点从不被键盘覆盖和用户能总是看到输入内容的部分。这个通常是不期望比调整大小,因为用户可能关闭软键盘以便获得与被覆盖内容的交互操作。
    上面的例子中,我们将AndroidManifest.xml的属性进行更改:android: windowSoftInputMode = "adjustPan"

    重新运行,并点击文本框,查看调试信息:
    E/onMeasure 6(8378): =>onMeasure called! widthMeasureSpec=1073742144, heightMeasureSpec=1073742200
    E/onMeasure 7(8378): =>onMeasure called! widthMeasureSpec=1073742144, heightMeasureSpec=1073742201
    E/onLayout 8(8378): =>OnLayout called! l=0, t=0,r=320,b=377
    我们看到:系统也重新进行了measrue和layout,但是我们发现,layout过程中onSizeChanged并没有调用,这说明输入法弹出前后并没有改变原有布局的大小。
    从下图的运行结果我们可以看到,下方的TextView并没有被顶到输入法上方。

    

    事实上,当输入框不会被遮挡时,该模式没有对布局进行调整,然而当输入框将要被遮挡时,窗口就会进行平移。也就是说,该模式始终是保持输入框为可见。如下图,整个窗口,包括标题栏均被上移,以保证文本框可见。

    

    模式三 自动模式
    当属性windowSoftInputMode被设置为adjustUspecified时,它不被指定是否该Activity主窗口调整大小以便留出软键盘的空间,或是否窗口上的内容得到屏幕上当前的焦点是可见的。系统将自动选择这些模式中一种主要依赖于是否窗口的内容有任何布局视图能够滚动他们的内容。如果有这样的一个视图,这个窗口将调整大小,这样的假设可以使滚动窗口的内容在一个较小的区域中可见的。这个是主窗口默认的行为设置。
    也就是说,系统自动决定是采用平移模式还是压缩模式,决定因素在于内容是否可以滚动。

    三、侦听软键盘的显示隐藏
    有时候,借助系统本身的机制来实现主窗口的调整并非我们想要的结果,我们可能希望在软键盘显示隐藏的时候,手动的对布局进行修改,以便使软键盘弹出时更加美观。这时就需要对软键盘的显示隐藏进行侦听。
    直接对软键盘的显示隐藏侦听的方法本人没有找到,如果哪位找到的方法请务必告诉本人一声。还有本方法针对压缩模式,平移模式不一定有效。
    我们可以借助软键盘显示和隐藏时,对主窗口进行了重新布局这个特性来进行侦听。如果我们设置的模式为压缩模式,那么我们可以对布局的onSizeChanged函数进行跟踪,如果为平移模式,那么该函数可能不会被调用。
    我们可以重写根布局,因为根布局的高度一般情况下是不发生变化的。
    假设跟布局为线性布局,模式为压缩模式,我们写一个例子,当输入法弹出时隐藏某个view,输入法隐藏时显示某个view。

  1. public class ResizeLayout extends LinearLayout{  
  2.     private OnResizeListener mListener; 
  3.      
  4.     public interface OnResizeListener { 
  5.         void OnResize(int w, int h, int oldw, int oldh); 
  6.     } 
  7.      
  8.     public void setOnResizeListener(OnResizeListener l) { 
  9.         mListener = l; 
  10.     } 
  11.      
  12.     public ResizeLayout(Context context, AttributeSet attrs) { 
  13.         super(context, attrs); 
  14.     } 
  15.      
  16.     @Override 
  17.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {     
  18.         super.onSizeChanged(w, h, oldw, oldh); 
  19.          
  20.         if (mListener != null) { 
  21.             mListener.OnResize(w, h, oldw, oldh); 
  22.         } 
  23.     } 

    在我们的Activity中,通过如下方法调用:

  1. public class InputMethodTestActivity extends Activity { 
  2.     private static final int BIGGER = 1
  3.     private static final int SMALLER = 2
  4.     private static final int MSG_RESIZE = 1
  5.      
  6.     private static final int HEIGHT_THREADHOLD = 30
  7.      
  8.     class InputHandler extends Handler { 
  9.         @Override 
  10.         public void handleMessage(Message msg) { 
  11.             switch (msg.what) { 
  12.             case MSG_RESIZE: { 
  13.                 if (msg.arg1 == BIGGER) { 
  14.                     findViewById(R.id.bottom_layout).setVisibility(View.VISIBLE); 
  15.                 } else { 
  16.                     findViewById(R.id.bottom_layout).setVisibility(View.GONE); 
  17.                 } 
  18.             } 
  19.                 break
  20.  
  21.             default
  22.                 break
  23.             } 
  24.             super.handleMessage(msg); 
  25.         } 
  26.     } 
  27.      
  28.     private InputHandler mHandler = new InputHandler(); 
  29.      
  30.     /** Called when the activity is first created. */ 
  31.     @Override 
  32.     public void onCreate(Bundle savedInstanceState) { 
  33.         super.onCreate(savedInstanceState); 
  34.         setContentView(R.layout.main); 
  35.          
  36.         ResizeLayout layout = (ResizeLayout) findViewById(R.id.root_layout); 
  37.         layout.setOnResizeListener(new ResizeLayout.OnResizeListener() { 
  38.              
  39.             public void OnResize(int w, int h, int oldw, int oldh) { 
  40.                 int change = BIGGER; 
  41.                 if (h < oldh) { 
  42.                     change = SMALLER; 
  43.                 } 
  44.                                  
  45.                 Message msg = new Message(); 
  46.                 msg.what = 1
  47.                 msg.arg1 = change; 
  48.                 mHandler.sendMessage(msg); 
  49.             } 
  50.         }); 
  51.     } 

    这里特别需要注意的是,不能直接在OnResizeListener中对要改变的View进行更改,因为OnSizeChanged函数实际上是运行在View的layout方法中,如果直接在onSizeChange中改变view的显示属性,那么很可能需要重新调用layout方法才能显示正确。然而我们的方法又是在layout中调用的,因此会出现错误。因此我们在例子中采用了Handler的方法。

    

分享到:
评论

相关推荐

    Android 软键盘切换表情不会闪动

    这通常是因为软键盘弹出和隐藏时改变了屏幕高度,导致布局重新计算,从而影响到表情面板的显示。 为了解决这个问题,我们可以采取以下两种主要方法: 1. **获取软键盘的高度**: - 可以通过监听`onGlobalLayout()...

    Android键盘事件处理例子

    理解软键盘和硬件键盘事件的区别,学会使用TextWatcher和KeyListener,以及如何控制软键盘的显示与隐藏,将有助于构建更加用户友好的Android应用程序。通过实践和研究提供的案例,你将能够熟练地处理各种键盘交互...

    android 软键盘弹出动态改变UI布局(IM聊天窗口设计示例) 源码

    总之,这个源码示例提供了处理Android软键盘弹出动态改变UI布局的方法,特别是对于IM聊天窗口的设计,具有很高的参考价值。开发者可以通过深入研究这些代码,学习如何在软键盘弹出时优雅地调整布局,提升应用的交互...

    解决聊天界面,软键盘和表情框切换问题

    通过研究和学习这些代码,开发者可以更好地理解和掌握软键盘和表情框的处理方法。 总结来说,解决聊天界面软键盘和表情框切换问题,需要关注软键盘状态的监听、界面布局的动态调整、表情框的交互设计等方面。通过...

    Android应用源码之调用中的软键盘-IT计算机-毕业设计.zip

    这个"Android应用源码之调用中的软键盘"的毕业设计Demo,旨在帮助开发者理解如何在Android应用中实现软键盘的显示与管理。下面我们将深入探讨相关知识点。 1. **Android布局管理**:在Android中,软键盘的弹出与...

    QQ登录界面解决软键盘问题

    在Android开发中,软键盘与应用界面的交互问题是一个常见的挑战,尤其是在设计登录界面时。QQ登录界面的设计优雅地解决了这个问题,确保了用户体验的流畅。本文将深入探讨如何模仿QQ登录界面来解决软键盘遮挡输入框...

    Delphi XE 10.2 FMX 程序中避免输入焦点被虚拟键盘遮挡

    1. 监听键盘状态:`TVKBHelper`可能会有一个内部函数用于检测Android系统的软键盘是否打开。这通常是通过监听Android系统的窗口尺寸变化来实现的。 2. 自动调整布局:一旦检测到虚拟键盘弹出,`TVKBHelper`可以自动...

    应用源码之调用中的软键盘.zip

    本资源"应用源码之调用中的软键盘.zip"提供了关于Android系统中如何处理软键盘显示和隐藏的源码示例,适合进行代码学习和毕业设计的参考。下面我们将详细探讨这个主题。 1. **软键盘的自动弹出与隐藏** 在Android...

    软键盘弹出和收回的监听

    在Android开发中,软键盘的弹出和收回是常见的用户交互事件,特别是在输入框较多或者底部有固定元素的布局中,软键盘的显示与隐藏会影响到界面的布局和用户体验。因此,监听软键盘的状态变得尤为重要。本文将深入...

    Android安卓应用源码-键盘输入类源代码(5例).zip

    首先,我们要明白Android中的键盘输入分为软键盘和硬键盘两种。软键盘通常是手机屏幕底部弹出的虚拟键盘,而硬键盘则是物理设备上的按键。在Android中,我们通常关注的是软键盘的处理。 1. **EditText和...

    Android 设置Edittext获取焦点并弹出软键盘

    在Android开发中,有时我们需要在应用启动或某个特定操作后,让`EditText`控件自动获取...希望本文的内容对你在Android开发过程中有所帮助,如果你有更多关于`EditText`和软键盘管理的问题,欢迎继续深入研究和实践。

    EditText跟随键盘弹出,背景不动

    为了避免这种情况,可以考虑使用`KeyboardAwareScrollView`或`NestedScrollView`作为根布局,它们可以监听键盘的显示和隐藏,从而只移动EditText。 4. **自定义ViewGroup**: 如果上述方法无法满足需求,可以考虑...

    QQ登陆框软键盘简单实现.rar

    QQ登陆框软键盘简单实现是一个常见的编程任务,尤其在移动应用或者网页开发中,为了提高用户体验,有时会自定义软键盘来替代系统默认的输入方式。这个压缩包可能包含了一个简单的示例项目,用于演示如何在QQ登录界面...

    anroid自定义软键盘

    这是自定义软键盘的核心,它包含了一个可以显示自定义键盘的布局。 2. **设计键盘布局** 使用XML文件创建键盘布局,包括按键、样式和大小。常用的键有字母、数字、特殊符号等,可以根据需求添加自定义键。 3. **...

    安卓-Android类似淘宝电商搜索功能监听软键盘搜索事件延迟自动搜索以及时间排序的搜索历史记录的实现.rar

    - 搜索框可以设计为一个可收缩/展开的搜索栏,点击时显示软键盘,取消时隐藏。 - 可以添加清除搜索历史的选项,以及展示搜索建议等功能,提升用户体验。 6. **错误处理和调试**: 由于压缩包中的代码可能无法...

    Android背光控制

    在Android系统中,背光控制是一项关键功能,它涉及到设备显示屏、软键盘以及其他光照元素的亮度调节。Android背光控制不仅影响用户体验,还对设备的电池寿命有着直接的影响。下面我们将详细探讨Android系统中的背光...

    Keyboard软键盘

    为了解决这个问题,开发者需要对Activity或Fragment的布局进行适当的优化,以适应软键盘的弹出和隐藏。有几种常见的解决方案: 1. **调整根布局**:将根布局设置为`android.widget.ScrollView`或`androidx.core....

    android源码

    在"Test2"这个文件中,可能包含了实现这一功能的具体代码示例,开发者可以学习如何在自己的应用中正确调用和控制软键盘的显示和隐藏。此外,通过查看源码,开发者还能了解到Android系统是如何处理输入事件和与IME...

    VKey-Test.zip_android

    《Android虚拟键盘(Virtual Key)测试程序解析》 在移动设备的世界里,Android操作系统占据了重要的地位,而...通过深入学习和实践,开发者可以在这个过程中积累宝贵的Android软键盘开发经验,提升自己的专业能力。

    SoftKeyboardListenDemo:监听软键盘

    1. **软键盘监听原理**:在Android系统中,软键盘的显示和隐藏并没有直接的回调接口提供给开发者。通常,我们可以通过监听Activity的root view的高度变化来间接判断软键盘的状态。当软键盘弹出时,根布局的高度会...

Global site tag (gtag.js) - Google Analytics