监听软键盘的弹出与收起的实现方法
由于这周末单休,然后,然后,然后 我一个不小心几乎是睡了一天,深感恐怖,于是我觉得我得做点什么,就想到了前几天两个群友问的关于软键盘的问题,正好我之前在工作中处理过,所以便写个博客记录分享一下
在这里,我写两个实现的方法。
1.是利用OnLayoutChangeListener的监听,在这里我简单的说下过程,因为应群友大大的建议,写的注释还是挺多的,也比较简单 。
思路的话就是点击控件弹出软键盘,然后输入,点击添加则隐藏布局同时收起键盘,但是考虑到用户可能点击返回键,软键盘的收起键,关于返回键的话,我们可以监听实现,但是软键盘的收起键,我 我 我 还不知道(我只是个萌新,有知道的小伙子望告知一下子),但是这样要写3个监听比较繁琐,这时候就觉得要是找个软键盘监听的方法就好了,还是一样 关于软键盘监听的方法呢 我还是不知道,应该是没有。所以我这里是利用OnLayoutChangeListener监听布局间接实现的
下面直接上代码 MainActivity .java
public class MainActivity extends Activity implements View.OnLayoutChangeListener, View.OnClickListener {
Button btn_name,btn_01;
// 开始写输入法弹出的
private LinearLayout lin_01;
private EditText edit_01;
private TextView tv_01;
// 显示隐藏键盘用的
InputMethodManager m;
// 屏幕高度
private int screenHeight = 0;
// 软件盘弹起后所占高度阀值
private int keyHeight = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
btn_name = (Button) findViewById(R.id.btn_name);
btn_01 = (Button) findViewById(R.id.btn_01);
lin_01 = (LinearLayout) findViewById(R.id.lin_01);
edit_01 = (EditText) findViewById(R.id.edit_01);
tv_01 = (TextView) findViewById(R.id.tv_01);
// 实例化显示隐藏键盘用的,当前显示则隐藏,当前隐藏则显示
m = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
tv_01.setOnClickListener(this);
btn_name.setOnClickListener(this);
btn_01.setOnClickListener(this);
// 获取屏幕高度
screenHeight = this.getWindowManager().getDefaultDisplay().getHeight();
// 阀值设置为屏幕高度的1/3
keyHeight = screenHeight / 3;
}
// 监听软键盘弹出收起的
@Override
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
// old是改变前的左上右下坐标点值,没有old的是改变后的左上右下坐标点值
// 现在认为只要控件将Activity向上推的高度超过了1/3屏幕高,就认为软键盘弹起
if (oldBottom != 0 && bottom != 0 && (oldBottom - bottom > keyHeight)) {
Log.e("onLayoutChange===","监听到软键盘弹起");
APP.mToast("监听到软键盘弹起");
// 监听到软键盘弹起
} else if (oldBottom != 0 && bottom != 0
&& (bottom - oldBottom > keyHeight)) {
lin_01.setVisibility(View.GONE);
// 失去焦点
edit_01.setFocusable(false);
edit_01.setFocusableInTouchMode(false);
edit_01.setText("");
Log.e("onLayoutChange===","监听到软件盘关闭");
APP.mToast("监听到软件盘关闭");
// 监听到软件盘关闭
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_name:
// 点击添加按钮的代码
// 显示隐藏键盘用的,当前显示则隐藏,当前隐藏则显示
m.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
lin_01.setVisibility(View.VISIBLE);
// 获取焦点
edit_01.setFocusable(true);
edit_01.setFocusableInTouchMode(true);
// 显示光标
edit_01.requestFocus();// 获取焦点 光标出现
break;
case R.id.tv_01:
String edit_tian = edit_01.getText().toString().trim();
if (!APP.NotNull(edit_tian)) {
APP.mToast("请输入");
return;
}
// 显示隐藏键盘用的,当前显示则隐藏,当前隐藏则显示
m.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
APP.mToast(edit_tian);
break;
case R.id. btn_01:
startActivity(new Intent(MainActivity.this,KeyBoardActivity.class));
break;
}
}
@Override
public void onResume() {
super.onResume();
// 添加layout大小发生改变监听器
lin_01.addOnLayoutChangeListener(this);
}
这里是主要代码,因为常规来说输入法弹出的话高度是超过屏幕的1/3的,所以我们就以此判断,当然也不一定完全正确。欢迎提供更好的方法哦
顺便贴一下布局 activity_main.xml;
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clipToPadding="true"
android:fillViewport="true"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="15dp"
android:text="软键盘监听"
android:textSize="20sp" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<Button
android:id="@+id/btn_name"
android:text="点击弹出软键盘"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:id="@+id/btn_01"
android:text="点击跳转"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</LinearLayout>
</ScrollView>
<LinearLayout
android:id="@+id/lin_01"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:layout_marginBottom="3dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:orientation="horizontal"
android:visibility="gone">
<EditText
android:id="@+id/edit_01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:background="@drawable/details_set_a"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:textCursorDrawable="@drawable/color_cursor" />
<!-- android:textCursorDrawable="@drawable/color_cursor" -->
<!-- 光标颜色 -->
<TextView
android:id="@+id/tv_01"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="@drawable/collection_bg02"
android:gravity="center"
android:text="添加" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
2.是使用自定义布局,页面布局中包含ScrollVIew,在软键盘弹起后,布局的高度会发生改变,根据布局的高度来判断软键盘的状态。(无意中大大神博客中见到的,于是实现了下)
思路其实也差不多,都是根据布局底部高度来判断布局是否上移,主要代码都在onLayout中
下面直接上代码 KeyBoardActivity.java
public class KeyBoardActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_keyboard);
initView();
}
private void initView() {
KeyboardLayout mainView = (KeyboardLayout) findViewById(R.id.keyboardLayout1);
final TextView tv = (TextView) findViewById(R.id.testone_tv);
mainView.setOnkbdStateListener(new KeyboardLayout.onKybdsChangeListener() {
public void onKeyBoardStateChange(int state) {
switch (state) {
case KeyboardLayout.KEYBOARD_STATE_HIDE:
tv.setVisibility(View.VISIBLE);
APP.mToast("软键盘隐藏");
break;
case KeyboardLayout.KEYBOARD_STATE_SHOW:
tv.setVisibility(View.INVISIBLE);
APP.mToast("软键盘弹起");
break;
}
}
});
}
}
接下来是自定义的类,注释已经加在代码中了,应该不需要过多的解释了 KeyboardLayout.java
/**
* Created by 搬砖小能手 on 2017/4/24.
* 介绍:这个是自定义的布局,自定义布局可以继承各种常见布局。自定义布局有键盘状态改变监听器,可以通过注册监听器来监听软键盘状态。
*/
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.RelativeLayout;
public class KeyboardLayout extends RelativeLayout {
private static final String TAG = KeyboardLayout.class.getSimpleName();
public static final byte KEYBOARD_STATE_SHOW = -3;//软键盘弹起
public static final byte KEYBOARD_STATE_HIDE = -2;//软键盘隐藏
public static final byte KEYBOARD_STATE_INIT = -1;//初始
private boolean mHasInit;
private boolean mHasKeybord;
private int mHeight;
private onKybdsChangeListener mListener;
public KeyboardLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public KeyboardLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public KeyboardLayout(Context context) {
super(context);
}
/**
* 设置键盘状态监听器
*/
public void setOnkbdStateListener(onKybdsChangeListener listener){
mListener = listener;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (!mHasInit) {
mHasInit = true;
mHeight = b;//获取底部高度
if (mListener != null) {//初始状态
mListener.onKeyBoardStateChange(KEYBOARD_STATE_INIT);
}
} else {
mHeight = mHeight < b ? b : mHeight;
}
if (mHasInit && mHeight > b) {//大于则表示布局本遮挡或顶起
mHasKeybord = true;
if (mListener != null) {//弹出
mListener.onKeyBoardStateChange(KEYBOARD_STATE_SHOW);
}
Log.w(TAG, "show keyboard.......");
}
if (mHasInit && mHasKeybord && mHeight == b) {//布局曾被遮挡或顶起,且回到了初始高度
mHasKeybord = false;
if (mListener != null) {//收起
mListener.onKeyBoardStateChange(KEYBOARD_STATE_HIDE);
}
Log.w(TAG, "hide keyboard.......");
}
}
public interface onKybdsChangeListener{
public void onKeyBoardStateChange(int state);
}
}
主要代码都在onLayout中,注释也都有,主要就是获得布局初始高度于之后的对比
按照国际惯例,下面就是布局了 activity_keyboard.xml;
<com.mykeyboard.KeyboardLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keyboardLay"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:fillViewport="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:gravity="center"
android:text="软件盘弹起,我INVISIBLE!软键盘隐藏,我VISIBLE!"
android:layout_weight="1.0"
android:textColor="#000000"
android:textStyle="bold" />
<LinearLayout
android:id="@+id/lin_01"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:layout_marginBottom="3dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:orientation="horizontal">
<EditText
android:id="@+id/edit_01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:background="@drawable/details_set_a"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:textCursorDrawable="@drawable/color_cursor" />
<!-- android:textCursorDrawable="@drawable/color_cursor" -->
<!-- 光标颜色 -->
<TextView
android:id="@+id/tv_01"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="@drawable/collection_bg02"
android:gravity="center"
android:text="添加" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</com.mykeyboard.KeyboardLayout>
最后来一波Demo:点击跳转至下载
到这里也就结束了 ,我也休息去了,明天早上还要参加史诗级灾难片演出呢,嘿嘿
另外需要学习小伙伴可以加群!大家一起讨论哈哈!一起开车!本萌新推荐力推啊。群号:188089649!
上午又撸了一发,于是发现一种方法,在这里更新一下
利用的是ViewTreeObserver一个的内部接口实现的,在这里简单介绍一下
1. interface ViewTreeObserver.OnGlobalFocusChangeListener
当在一个视图树中的焦点状态发生改变时,所要调用的回调函数的接口类
2. interface ViewTreeObserver.OnGlobalLayoutListener
当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时,所要调用的回调函数的接口类
3. interface ViewTreeObserver.OnPreDrawListener
当一个视图树将要绘制时,所要调用的回调函数的接口类
4. interface ViewTreeObserver.OnScrollChangedListener
当一个视图树中的一些组件发生滚动时,所要调用的回调函数的接口类
5. interface ViewTreeObserver.OnTouchModeChangeListener
当一个视图树的触摸模式发生改变时,所要调用的回调函数的接口类
这里的话,我们可以利用OnGlobalLayoutListener来获得一个视图的真实高度。
但是需要注意的是OnGlobalLayoutListener可能会被多次触发,因此在得到了高度之后,要将OnGlobalLayoutListener注销掉。
原理的话和上面的也是大同小异,就不多作解释了,就直接上代码了
GlobalLayoutActivity.java
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.mykeyboard.R;
import com.mykeyboard.app.APP;
import com.mykeyboard.widget.KeyboardChangeListener;
/**
* abc
* Created by 搬砖小能手 on 2017/4/24.
* E-mail:40492459@qq.com.
* Signature:当你的才华满足不了你的野心的时候,那么你应该静下心来学习.
* Alert:语言的巨人,行动的矮子!
*/
public class GlobalLayoutActivity extends Activity implements KeyboardChangeListener.KeyBoardListener{
private KeyboardChangeListener mKeyboardChangeListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_globallayout);
initView();
}
private void initView(){
mKeyboardChangeListener = new KeyboardChangeListener(this);
mKeyboardChangeListener.setKeyBoardListener(this);
}
@Override
public void onKeyboardChange(boolean isShow, int keyboardHeight) {
Log.d("GlobalLayoutActivity==", "onKeyboardChange() called with: " + "isShow = [" + isShow + "], keyboardHeight = [" + keyboardHeight + "]");
APP.mToast("软键盘="+isShow+",高度差=keyboardHeight=="+keyboardHeight);
}
}
这里的话比较简单,没啥要注意的,主要是KeyboardChangeListener中,
KeyboardChangeListener.java
public class KeyboardChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {
private static final String TAG = "ListenerHandler";
private View mContentView;
private int mOriginHeight;
private int mPreHeight;
private KeyBoardListener mKeyBoardListen;
public interface KeyBoardListener {
/**
* call back
* @param isShow true is show else hidden
* @param keyboardHeight keyboard height
*/
void onKeyboardChange(boolean isShow, int keyboardHeight);
}
public void setKeyBoardListener(KeyBoardListener keyBoardListen) {
this.mKeyBoardListen = keyBoardListen;
}
public KeyboardChangeListener(Activity contextObj) {
if (contextObj == null) {
Log.i(TAG, "contextObj is null");
return;
}
mContentView = findContentView(contextObj);
if (mContentView != null) {
addContentTreeObserver();
}
}
private View findContentView(Activity contextObj) {
return contextObj.findViewById(android.R.id.content);
}
private void addContentTreeObserver() {
mContentView.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
public void onGlobalLayout() {
int currHeight = mContentView.getHeight();//初始高度
if (currHeight == 0) {
Log.i(TAG, "currHeight is 0");
return;
}
boolean hasChange = false;
if (mPreHeight == 0) {
mPreHeight = currHeight;
mOriginHeight = currHeight;
} else {
if (mPreHeight != currHeight) {//说明布局变化了,
hasChange = true;
mPreHeight = currHeight;
} else {//又变化了,这里默认回到了初始状态
hasChange = false;
}
}
if (hasChange) {//弹出状态
boolean isShow;
int keyboardHeight = 0;
if (mOriginHeight == currHeight) {//mOriginHeight,初始高度
//hidden
isShow = false;
} else {
//show
keyboardHeight = mOriginHeight - currHeight;//键盘高度
isShow = true;
}
if (mKeyBoardListen != null) {
mKeyBoardListen.onKeyboardChange(isShow, keyboardHeight);
}
}
}
/**
* 注销
*/
public void destroy() {
if (mContentView != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mContentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
}
}
在这里值得注意的就是巧妙的利用了一个系统布局
private View findContentView(Activity contextObj) {
return contextObj.findViewById(android.R.id.content);
}
好了 就这样 另外给个新的Demo
如果各位小伙伴有更好的实现方法 ,分享一下哦,以前学习