转自: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. CCF CSP 201709-4 通信网络

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201709-4 通信网络 问题描述 某国的军队由N个部门组成,为了提高安全性,部门之间建立了M ...

  2. linux ncat命令

    netcat是网络工具中的瑞士军刀,它能通过TCP和UDP在网络中读写数据.通过与其他工具结合和重定向,你可以在脚本中以多种方式使用它.使用netcat命令所能完成的事情令人惊讶. netcat所做的 ...

  3. python实现获取系统版本和mac信息上传到指定接口

    import os,platform,uuid,urllib.parse,urllib.request,json def BeforeSystemRequests(): ''' the systemi ...

  4. MVC 源码调试

    源码调试,帮助你跟好理解MVC,使你开发跟牛B的程序. 1>在Visual命令行中运行“SN.EXE-Vr*,31BF3856AD364E35” 2. codeplex.com 上面找到,和你当 ...

  5. 【51nod】1149 Pi的递推式

    题解 我们把这个函数的递归形式画成一张图,会发现答案是到每个出度为0的点的路径的方案数 这个可以用组合数算 记录一下P[i]为i减几次PI减到4以内 如果P[i + 1] > P[i],那么转向 ...

  6. BC-NFS安装依赖

    [root@BC-NFS01 glusterFS_installer]# sh install_local.sh 18-09-19 22:43:28 [install_local.sh] INFO : ...

  7. 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.jee.server:fhcq-oa' did not find a matching property.

    当你在使用Eclipse运行web项目时,你可能会看到控制台出现: 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Settin ...

  8. ASP.NET MVC中在Action获取提交的表单数据方法

    有Index视图如下: 视图代码如下: <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Mas ...

  9. [ 转载 ] Mysql 远程连接+开放80和3306端口 常用配置

    直接上方法: 首先配置CentOS下防火墙iptables规则: # vim /etc/sysconfig/iptables 向其中加入下列规则: -A INPUT -m state –state N ...

  10. [ 原创 ]学习笔记- 数据在Activity之间的传递的情况

    情况一:一个Activity跳转到另一个Activity时,将第一个Activity的数据传递到第二个Activity里面. 分析:当一个界面跳转到另一个界面的同时还要讲数据传递过去,这种情况需要用I ...