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

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

. public class ResizeLayout extends LinearLayout{
. private static int count = ;
.
. public ResizeLayout(Context context, AttributeSet attrs) {
. super(context, attrs);
. }
.
. @Override
. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
. super.onSizeChanged(w, h, oldw, oldh);
.
. Log.e("onSizeChanged " + count++, "=>onResize called! w="+w + ",h="+h+",oldw="+oldw+",oldh="+oldh);
. }
.
. @Override
. protected void onLayout(boolean changed, int l, int t, int r, int b) {
. super.onLayout(changed, l, t, r, b);
. Log.e("onLayout " + count++, "=>OnLayout called! l=" + l + ", t=" + t + ",r=" + r + ",b="+b);
. }
.
. @Override
. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
.
. Log.e("onMeasure " + count++, "=>onMeasure called! widthMeasureSpec=" + widthMeasureSpec + ", heightMeasureSpec=" + heightMeasureSpec);
. }

我们的布局设置为:

. <com.winuxxan.inputMethodTest.ResizeLayout
. xmlns:android="http://schemas.android.com/apk/res/android"
. android:id="@+id/root_layout"
. android:layout_width="fill_parent"
. android:layout_height="fill_parent"
. android:orientation="vertical"
. >
.
. <EditText
. android:layout_width="fill_parent"
. android:layout_height="wrap_content"
. />
.
. <LinearLayout
. android:id="@+id/bottom_layout"
. android:layout_width="fill_parent"
. android:layout_height="fill_parent"
. android:orientation="vertical"
. android:gravity="bottom">s
.
. <TextView
. android:layout_width="fill_parent"
. android:layout_height="wrap_content"
. android:text="@string/hello"
. android:background="#77777777"
. />
. </LinearLayout>
. </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。

 . public class ResizeLayout extends LinearLayout{
. private OnResizeListener mListener;
.
. public interface OnResizeListener {
. void OnResize(int w, int h, int oldw, int oldh);
. }
.
. public void setOnResizeListener(OnResizeListener l) {
. mListener = l;
. }
.
. public ResizeLayout(Context context, AttributeSet attrs) {
. super(context, attrs);
. }
.
. @Override
. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
. super.onSizeChanged(w, h, oldw, oldh);
.
. if (mListener != null) {
. mListener.OnResize(w, h, oldw, oldh);
. }
. }
. } 在我们的Activity中,通过如下方法调用:
源码打印?
. public class InputMethodTestActivity extends Activity {
. private static final int BIGGER = ;
. private static final int SMALLER = ;
. private static final int MSG_RESIZE = ;
.
. private static final int HEIGHT_THREADHOLD = ;
.
. class InputHandler extends Handler {
. @Override
. public void handleMessage(Message msg) {
. switch (msg.what) {
. case MSG_RESIZE: {
. if (msg.arg1 == BIGGER) {
. findViewById(R.id.bottom_layout).setVisibility(View.VISIBLE);
. } else {
. findViewById(R.id.bottom_layout).setVisibility(View.GONE);
. }
. }
. break;
.
. default:
. break;
. }
. super.handleMessage(msg);
. }
. }
.
. private InputHandler mHandler = new InputHandler();
.
. /** Called when the activity is first created. */
. @Override
. public void onCreate(Bundle savedInstanceState) {
. super.onCreate(savedInstanceState);
. setContentView(R.layout.main);
.
. ResizeLayout layout = (ResizeLayout) findViewById(R.id.root_layout);
. layout.setOnResizeListener(new ResizeLayout.OnResizeListener() {
.
. public void OnResize(int w, int h, int oldw, int oldh) {
. int change = BIGGER;
. if (h < oldh) {
. change = SMALLER;
. }
.
. Message msg = new Message();
. msg.what = ;
. msg.arg1 = change;
. mHandler.sendMessage(msg);
. }
. });
. }
. }

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

原文:http://blog.csdn.net/yuzhiboyi/article/details/7835183

Android 软键盘监听事件的更多相关文章

  1. 完美解决android软键盘监听

    最近在做应用性能调优,发现在一个包含有输入框的Activity中,当软键盘弹出的时候,如果直接finish掉此Activity,那么在返回到上一个Activity时,界面的渲染会由于软键盘没有及时的收 ...

  2. android 软键盘监听显示和隐藏

    githup中找到:https://github.com/yescpu/KeyboardChangeListener import android.app.Activity; import andro ...

  3. js 获取当前焦点所在的元素、给元素和input控件添加键盘监听事件、添加页面级的键盘监听事件

    页面级的键盘监听事件 document.onkeydown = function (event) { var e = event || window.event || arguments.callee ...

  4. [置顶] java Gui 键盘监听事件

    简单写一个java Gui键盘监听事件,实现的效果就是按下键盘控制台输出你按下的键.比如:按下A控制台就输出A 效果如图: 以下把实现的效果分为几个步骤: 1.新建一个窗体类继承窗体: 2.给这个窗体 ...

  5. JPanel添加键盘监听事件

    因为在自己的游戏需求中谢了要用键盘控制飞机的移动,所以用到键盘监听事件,但是使用了JPanel之后添加了键盘监听事件,按相应的方向键飞机并没有反应.但是如果是为JFrame的内容面板加则会有反应. 为 ...

  6. Android之键盘监听的执行机理【看清键盘监听的本质】【入门版】

    以EditText为例: 1.Activity本身也有按键监听 editText按键监听与Activity按键监听关系: Activity本身也有按键监听 并且分按下和松开两个事件监听 editTex ...

  7. Android 属性动画监听事件与一个菜单的例子

    简单监听事件 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 3 ...

  8. Android CheckBox的监听事件

    1.在xml文件中定义CheckBox,一定要定义id <CheckBox android:id="@+id/beijing" android:layout_width=&q ...

  9. android listview 的监听事件

    今天遇到了一个比较让我头疼的问题,不过追根揭底只是我对listview理解的不够透彻罢了, 闲言少叙,说说我遇到的问题吧: 上篇随笔我写了关于listview的使用,如果你也已经写好了列表那么恭喜这一 ...

随机推荐

  1. IPod在Linux下的实战

    刚收到一个朋友送的Ipod,经过研究今天我为大家分享一点在Linux系统下使用的经验.Apple的iPod它炫目时尚,超薄还可以俘储大量歌曲,这使得iPod十分流行.但流行的同时也带来了一些问题, 在 ...

  2. InstallShield详细制作说明(三)

    八.许可协议 打开[Installation Designer]->[Behavior and Logic]->[Support Files/Billboards]面板 这里[Langua ...

  3. js 关于网易淘宝移动端适配的学习

    (function (doc, win) { // orientationchange:用户水平或者垂直翻转设备(即方向发生变化)时触发的事件;(屏幕大小发生变化) var docEl = doc.d ...

  4. python 时间合集 一

    **以下内容均为我个人的理解,如果发现错误或者疑问可以联系我共同探讨**#### python中4种时间表示形式:1.格式化时间字符串 2.时间戳 3.时间元祖 4.时间对象- string_time ...

  5. 使用C#对XML进行增删改查操作

    xml文件格式 <?xml version="1.0" encoding="utf-8"?> <messageList> <mes ...

  6. 洛谷 P1327 数列排序

    P1327 数列排序 题目描述 给定一个数列{an},这个数列满足ai≠aj(i≠j),现在要求你把这个数列从小到大排序,每次允许你交换其中任意一对数,请问最少需要几次交换? 输入输出格式 输入格式: ...

  7. 字串乱序 PHP&JS

    <?php /** * 字串乱序 PHP&JS * * php 中把字串乱序后输出给客户机的 JAVASCRIPT , JAVASCRIPT 中恢复 * 在指定长度提取一个字符,并把这一 ...

  8. bootstrap课程7 jquery中结束之前动画用什么

    bootstrap课程7 jquery中结束之前动画用什么 一.总结 一句话总结:stop()方法.$('.navs').not($('.navs').eq(idx)).stop().hide(100 ...

  9. web自动化测试 Selenium2 Java自动化测试实战9_3

    driver.findElement(By.id("idInput")).sendKeys("哈哈"); driver.findElement(By.id(&q ...

  10. 注意knn与kmeans的区别

    开始的时候,我居然弄混了. knn是分类方法,是通过新加入的节点最接近的N个节点的属性,来判定新的节点. kmeans是聚类方法,是先选择k个点作为k个簇的中点,然后分簇之后重新划定中心点,然后再分簇 ...