转自:http://blog.csdn.net/lilu_leo/article/details/6587578

看了很多这类型的文章,这篇文章最有价值,解决了我的烦恼,必须转。

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

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

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

我们的布局设置为:

  1. 1. <com.winuxxan.inputMethodTest.ResizeLayout
  2. 2.     xmlns:android="http://schemas.android.com/apk/res/android"
  3. 3.     android:id="@+id/root_layout"
  4. 4.     android:layout_width="fill_parent"
  5. 5.     android:layout_height="fill_parent"
  6. 6.     android:orientation="vertical"
  7. 7.     >
  8. 8.
  9. 9.     <EditText
  10. 10.         android:layout_width="fill_parent"
  11. 11.         android:layout_height="wrap_content"
  12. 12.     />
  13. 13.
  14. 14.     <LinearLayout
  15. 15.             android:id="@+id/bottom_layout"
  16. 16.             android:layout_width="fill_parent"
  17. 17.             android:layout_height="fill_parent"
  18. 18.             android:orientation="vertical"
  19. 19.             android:gravity="bottom">s
  20. 20.
  21. 21.     <TextView
  22. 22.         android:layout_width="fill_parent"
  23. 23.         android:layout_height="wrap_content"
  24. 24.         android:text="@string/hello"
  25. 25.         android:background="#77777777"
  26. 26.       />
  27. 27.    </LinearLayout>
  28. 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. 1. public class ResizeLayout extends LinearLayout{
  2. 2.     private OnResizeListener mListener;
  3. 3.
  4. 4.     public interface OnResizeListener {
  5. 5.         void OnResize(int w, int h, int oldw, int oldh);
  6. 6.     }
  7. 7.
  8. 8.     public void setOnResizeListener(OnResizeListener l) {
  9. 9.         mListener = l;
  10. 10.     }
  11. 11.
  12. 12.     public ResizeLayout(Context context, AttributeSet attrs) {
  13. 13.         super(context, attrs);
  14. 14.     }
  15. 15.
  16. 16.     @Override
  17. 17.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  18. 18.         super.onSizeChanged(w, h, oldw, oldh);
  19. 19.
  20. 20.         if (mListener != null) {
  21. 21.             mListener.OnResize(w, h, oldw, oldh);
  22. 22.         }
  23. 23.     }
  24. 24. }

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

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

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

Android之Android软键盘的隐藏显示研究的更多相关文章

  1. Android软键盘的隐藏显示研究

    http://winuxxan.blog.51cto.com/2779763/522810 全局推: android:windowSoftInputMode="adjustResize&qu ...

  2. Android软键盘的隐藏显示、事件监听的代码

    把开发过程中重要的一些内容片段做个珍藏,如下资料是关于Android软键盘的隐藏显示.事件监听的内容,应该是对小伙伴们有所用途. public class ResizeLayout extends L ...

  3. android:windowSoftInputMode属性;界面关闭后软键盘不隐藏的解决方法;

    stateUnspecified:软键盘的状态并没有指定,系统将选择一个合适的状态或依赖于主题的设置 stateUnchanged:当这个activity出现时,软键盘将一直保持在上一个activit ...

  4. android 弹出软键盘将底部视图顶起问题

    今天要做一个搜索功能,搜索界面采用AutoCompleteTextView做搜索条,然后下面用listview来显示搜索结果,而我的主界面是在底 部用tab做了一个主界面导航,其中有一个搜索按钮,因为 ...

  5. 彻底搞定Android开发中软键盘的常见问题

    软键盘显示的原理 软件盘的本质是什么?软键盘其实是一个Dialog.        InputMethodService为我们的输入法创建了一个Dialog,并且将该Dialog的Window的某些参 ...

  6. 调用Android中的软键盘

    我们在Android提供的EditText中单击的时候,会自动的弹 出软键盘,其实对于软键盘的控制我们可以通过InputMethodManager这个类来实现.我们需要控制软键盘的方式就是两种一个是像 ...

  7. Android 监听软键盘按键的三种方式

    前言: 我们在Android手机上面有时候会遇到监听手机软键盘按键的时候,例如:我们在浏览器输入url完毕后可以点击软键盘右下角的“Go”按键加载url页面:在点击搜索框的时候,点击右下角的searc ...

  8. Android中检测软键盘的弹出和关闭

    Android系统并没有提供明显的API来监听软键盘的弹出和关闭,但是在某些情况下我们还是有办法来检测软键盘的弹出和关闭. 从StackOverflow找到了一个不错的方法.但是这种只适用于在mani ...

  9. Android 监听软键盘搜索键

    现在很多的Android应用都有了数据搜索功能,在以往的设计上,会使用搜索框+搜索按钮来实现搜索功能: 现在呢,越来越流行的是,去除搜索按钮,直接监听软键盘搜索键,当用户输入完搜索关键字后,直接点击软 ...

随机推荐

  1. 继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类。 (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法。 (3)子类中定义的成员变量和父类中定义的成员变量相同时,则父类中的成员变量不能被继承。 (4)子类中定义的成员方法,并且这个方法的名字返回类型,以及参数个数和类型与父类的某个成员方法完全相同,则父类的成员方法不能被继承。 分析以上程

    继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类. (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法.(3)子类中定义的成员变量和父类中定义的 ...

  2. loadrunner学习笔记之参数设置

    一.关于参数的定义 在你录制程序运行的过程中,脚本生成器自动生成由函数组成的用户脚本.函数中参数的值就是在录制过程中输入的实际值. 例如,你录制了一个Web应用程序的脚本.脚本生成器生成了一个声明,该 ...

  3. 【转】TCP建立连接三次握手和释放连接四次握手

    在谈及TCP建立连接和释放连接过程,先来简单认识一下TCP报文段首部格式的的几个名词(这里只是简单说明,具体请查看相关教程) 序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数 ...

  4. Python并发编程系列之常用概念剖析:并行 串行 并发 同步 异步 阻塞 非阻塞 进程 线程 协程

    1 引言 并发.并行.串行.同步.异步.阻塞.非阻塞.进程.线程.协程是并发编程中的常见概念,相似却也有却不尽相同,令人头痛,这一篇博文中我们来区分一下这些概念. 2 并发与并行 在解释并发与并行之前 ...

  5. 标准c库函数与Linux下系统函数库 区别 (即带不带缓冲区的学习)

    我们都知道,C语言在UNIX/Linux系统下有一套系统调用(系统函数),比如文件操作open().close().write().read()等,而标准C语言的库函数中也有一套对文件的操作函数fop ...

  6. [转载] 你所不知道的TIME_WAIT和CLOSE_WAIT

    前言 本文转载自 https://mp.weixin.qq.com/s/FrEfx_Yvv0fkLG97dMSTqw.很久前看到Vincent Bernat在博客中写了一遍关于TCP time-wai ...

  7. fast协议解读

    目录 背景 fast协议特征 fast协议解读 背景 股票行情一般传输的数据类型为: int / long / float /double / string 来表示行情价格成交量之类的数据. 正常传输 ...

  8. jQuery中bind,live,delegate,on的区别

    bind(),live()都是调用on()函数,只不过传递的参数不同. 一.$(selector).bind(event,data,fn); $('#J_btn').bind('click',func ...

  9. PreEssentials与MFC集成使用

    ProEssentials是Gigasoft公司开发的一个功能十分强大的分发免费的工控图表.它提供了几乎所有的曲线显示形式,支持多种开发工具,提供以下接口供开发者调用:.NET(WinForm).AS ...

  10. ngx_lua配置及应用

    一.说明 这里不对lua语言本身及其编译器运行环境等做介绍,以下所有介绍前提对lua相关有所了解. 二.ngx_lua介绍 原理 ngx_lua将Lua嵌入Nginx,可以让Nginx执行Lua脚本, ...