感谢 群里大神 谷歌的小弟

在Activity中含有EditText时,我们常常在AndroidManifest.xml中为该Activity设置Android:windowSoftInputMode属性,其中最常用的值就是adjustResize和adjustPan。在此请思考几个问题:

  • adjustResize和adjustPan有什么区别?
  • adjustResize和adjustPan的应用场景有何差异?
  • 当设置android:windowSoftInputMode后如何监听软键盘的弹起与隐藏?

1.干嘛要去监听软键盘的弹起呢?有什么用呢?

当键盘弹起来的时候在紧靠键盘上方的地方出现了一个自定义布局,点击笑脸就可以发送专属emoji表情,点击礼盒就可以发送福利。
当然,在键盘收起的时候这个布局也就不可见了。

除此以外,在其他不少场景也会有类似的UI设计。在这些情况下,我们都要监听键盘软键盘的弹起与隐藏。善良的童鞋会想:这个没难度呀,调用一下官方的API就行。很久以前,我也是这么想的。可是,事与愿违,官方文档中根本就没有提供检测软键盘状态的接口。

既然官方没有把这个API洗干净整整齐齐的摆在眼前,那我们就自己实现它

2. adjustResize

在AndroidManifest.xml中为该Activity设置

android:windowSoftInputMode="adjustResize"

该模式下系统会调整屏幕的大小以保证软键盘的显示空间。

eg: 屏幕的高为1920px,那么整个Activity的布局高度也为1920px。当设置该属性后点击界面中的EditText,此时弹出软键盘其高度为800px。为了完整地显示此软键盘,系统会调整Activity布局的高度为1920px-800px=1120px。

所以,此时的布局与原本的布局就发生了一些变化,比如:整体布局显示不完整,控件外观的变形,控件显示位置的错乱等等。这些现象都是因为原布局的高度变小所导致

结合代码分析

package com.lizi.softpan;import android.content.Context;import android.util.AttributeSet;import android.widget.RelativeLayout;/** * Created by lizi on 2017/2/22. */public class RelativeLayoutSubClass extends RelativeLayout {    private OnSoftKeyboardListener mSoftKeyboardListener;    public RelativeLayoutSubClass(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        System.out.println("----> onMeasure");    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        super.onLayout(changed, l, t, r, b);        mSoftKeyboardListener.onSoftKeyboardChange();        System.out.println("----> onLayout");    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        System.out.println("----> onSizeChanged");    }    public void setSoftKeyboardListener(OnSoftKeyboardListener listener){        mSoftKeyboardListener=listener;    }    public interface OnSoftKeyboardListener{        public void onSoftKeyboardChange();    }}
package com.lizi.softpan;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;public class MainActivity extends AppCompatActivity {    private RelativeLayoutSubClass mRootLayout;    private int screenHeight;    private int screenWidth;    private int threshold;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        init();    }    private void init(){        screenHeight=getResources().getDisplayMetrics().heightPixels;        screenWidth=getResources().getDisplayMetrics().widthPixels;        threshold=screenHeight/3;        mRootLayout= (RelativeLayoutSubClass) findViewById(R.id.rootLayout);        mRootLayout.setSoftKeyboardListener(new RelativeLayoutSubClass.OnSoftKeyboardListener() {            @Override            public void onSoftKeyboardChange() {                System.out.println("Main ----> onSizeChanged");            }        });    }}
<?xml version="1.0" encoding="utf-8"?><com.lizi.softpan.RelativeLayoutSubClass    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/rootLayout"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context=".MainActivity">    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="200dp"        android:layout_alignParentTop="true"        android:background="#7fb80e">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="浅绿色部分在屏幕顶部"            android:textSize="25sp"            android:layout_centerInParent="true"            android:textColor="#843900"/>    RelativeLayout>    <EditText        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:hint="这里是一个输入框"        android:textSize="25sp"        android:layout_centerInParent="true"        android:textColor="#843900"/>    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="200dp"        android:layout_alignParentBottom="true"        android:background="#ffc20e">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="浅黄色部分在屏幕底部"            android:textSize="25sp"            android:layout_centerInParent="true"            android:textColor="#f05b72"/>    RelativeLayout>com.lizi.softpan.RelativeLayoutSubClass>

点击 edittext

当软键盘状态变化的时候RelativeLayoutSubClass中有哪些行为发生:

1.软键盘状态变化时会调用其onMeasure(),onLayout(),onSizeChanged()2.在onSizeChanged()中可以确知软键盘状态变化前后布局宽高的数值

至此,发现一个关键点:onSizeChanged()
我们可以以此为切入点检测软键盘的状态变化,当软键盘状态发生改变时,通过对Activity布局文件中Layout对onSizeChanged()判断软键盘的弹起或隐藏

3. adjustPan

在AndroidManifest.xml中为该Activity设置

android:windowSoftInputMode=”adjustPan”

该模式下系统会将界面中的内容自动移动从而使得焦点不被键盘覆盖,即用户能总是看到输入内容的部分

比如,还是刚才的那个布局,现在将其windowSoftInputMode设置为adjustPan再点击EditText,效果如下:

为了避免软键盘弹起后遮挡EditText,系统将整个布局上移了,也就是我们常说的将布局顶上去了

此时再来看看当软键盘状态变化的时候RelativeLayoutSubClass中有哪些行为发生:

1.软键盘状态变化时会调用其onMeasure(),onLayout()2.onSizeChanged()并没有被调用3.整个布局的高度也没有变化

这时并没有执行onSizeChanged()方法,这也就说原本检测软键盘状态的方法在这就行不通了,得另辟蹊径了。

当软键盘弹起时,原布局中是不是有一部分被键盘完全遮挡了呢?
对吧,也就是说原布局的可视范围(更精确地说是可视高度)发生了变化:变得比以前小了。所以,我们可以以此为突破口,具体代码如下:

    public boolean isSoftKeyboardShow(View rootView) {        screenHeight = getResources().getDisplayMetrics().heightPixels;        screenWidth = getResources().getDisplayMetrics().widthPixels;        System.out.println("screenHeight ----> "+screenHeight);        System.out.println("screenWidth ----> "+screenWidth);        threshold = screenHeight/3;        //获取根布局(RelativeLayoutSubClass)原本的高度        int rootViewBottom = rootView.getBottom();        //获取根布局(RelativeLayoutSubClass)原本的高度        Rect rect = new Rect();        rootView.getWindowVisibleDisplayFrame(rect);        int visibleBottom = rect.bottom;        //计算两者的差值        int heightDiff = rootViewBottom - visibleBottom;        System.out.println("----> rootViewBottom="+rootViewBottom+",visibleBottom="+visibleBottom);        System.out.println("----> heightDiff="+heightDiff+",threshold="+threshold);        //判断软键盘是否弹起        return heightDiff > threshold;    }

至此当windowSoftInputMode设置为adjustPan时软键盘的状态监听也得到了实现

4. 源码

https://github.com/aixiaozi/SoftInputMode

更多相关文章

  1. Android如何检测输入法键盘是否显示
  2. 【Android】Android(安卓)SurfaceFlinger之BufferQueue
  3. Android控件显示和隐藏
  4. Android(安卓)SharedPreferences保存登录状态
  5. android shape的使用
  6. Android(安卓)Weekly Notes Issue #232
  7. android应用 小试牛刀 开发自己的应用程序就是这么简单
  8. Android(安卓)Power Management
  9. Android中Activity状态的保存和恢复:onSaveInstanceState和onRest

随机推荐

  1. android 文件系统分析
  2. Google Android SDK 2.1正式发布
  3. Android调用WebService之服务端实现(一)
  4. 李开复解读Gphone Android和手机联盟
  5. android 事件机制,捕捉与事件监听总结整理
  6. Android中多线程的handler与Thread
  7. Android 默认Tab标签大小及间距修改
  8. View 的绘制流程
  9. Android群英传第五章Scroll分析读书笔记
  10. Android多渠道打包,Android签名包,Android