转自: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. 使用PHP写了一个图片分割等份工具,便于前台页面切图时使用。

    目的: 由于网站更新活动较频繁,其大多数以静态图片为主,设计人员在除了设计图后都要给前端制作人员再次切图从而达到页面加载图片缓慢的问题,为了减少工作量做了该工具. 功能: 上传一张图,将其分割成指定等 ...

  2. thinkphp3.2中开启静态缓存后对404页面的处理方法

    静态缓存很实用但是有时有些不需要静态缓存,如404页面,第一次访问返回404页面并缓存,第二次换回的状态就是200,属于正常访问,虽然人眼可以看出是404页面,但是搜索引擎不会的,而是把这个页面当成正 ...

  3. 【知了堂学习笔记】java IO流归纳总结

    皮皮潇最近学到了IO流但是感觉这一块要记的东西太多了,所以重API上查阅并总结了以下几点关于IO的知识. 1.File(文件类): File类是文件以及文件夹进行封装的对象,用对象的思想来操作文件和文 ...

  4. iOS 11开发教程(十)iOS11无线连接手机真机测试

    iOS 11开发教程(十)iOS11无线连接手机真机测试 在Xcode 9.0中,已经可以通过无线连接手机进行真机测试了.具体的操作步骤如下: (1)首先需要使用数据线将手机连接到苹果电脑上. (2) ...

  5. 整理之DOM事件阶段、冒泡与捕获、事件委托、ie事件和dom模型事件、鼠标事件

    整理之DOM事件阶段 本文主要解决的问题: 事件流 DOM事件流的三个阶段 先理解流的概念 在现今的JavaScript中随处可见.比如说React中的单向数据流,Node中的流,又或是今天本文所讲的 ...

  6. Centos 安装 WPS

    Linux有自己的一套类是Office的办公软件:LibreOffice,但是不是很友好,幸好WPS有Linux版本. 安装步骤: 1.安装依赖包 yum install libpng12 yum i ...

  7. JSTL介绍

    JSTL介绍 一.介绍 JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能. JSTL支持通用的.结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标 ...

  8. codevs 2292 图灵机游戏

    2292 图灵机游戏  时间限制: 1 s  空间限制: 64000 KB  题目等级 : 黄金 Gold   题目描述 Description [Shadow 1]第二题 Shadow最近知道了图灵 ...

  9. BZOJ.4516.[SCOI2016]幸运数字(线性基 点分治)

    题目链接 线性基可以\(O(log^2)\)暴力合并.又是树上路径问题,考虑点分治. 对于每个点i求解 LCA(u,v)==i 时的询问(u,v),只需求出这个点到其它点的线性基后,暴力合并. LCA ...

  10. 转 MySQL连接超时

    在负载较重的MySQL服务器上,有时你偶尔会看到一些连接超时的错误,诸如: Can’t connect to MySQL server on ‘mydb’(110).如果当时你有多个连接请求,你会发现 ...