我们在开发中经常会遇到软键盘遮挡住了输入框,而直接把输入框往上顶adjustResize这种方法过于暴力影响美观,我们希望键盘弹出时动态的去改变布局。这时候,便用到了监听键盘弹起事件的功能。
可能
大家都会潜意识觉得:Android中没有可以复写的方法么?或者说,没有什么listener可以让我们使用么?
抱歉,真的没有,我们潜意识都是以为系统会提供,其实系统提供的是InputMethodManager,让我们控制键盘的弹出和隐藏,而不是键盘弹出和隐藏触发事件。
Android系统并没有给我们提供监听键盘弹出的方法,同样,Android系统也没有给我们提供获取软键盘的高度的方法,我们只能自己监听view的高度变化来间接判断键盘是不是弹出了,并通过计算获取软键盘的高度。
目前通用的方法是,由于键盘弹起与隐藏,会使得layout的布局发生变化,通过布局的大小变化触发的事件实现键盘事件的触发。
重写 onSizeChanged - 麻烦,不推荐
不要忘了设置键盘
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
1
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
自定义一个ViewGroup
public class AdjustSizeRelativeLayout extends RelativeLayout {
public AdjustSizeRelativeLayout(Context context) {
super(context);
}
public AdjustSizeRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public AdjustSizeRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
private static final int CHANGE_SIZE = 200;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Log.i("bqt", "【onSizeChanged】" + w + " " + h + " " + oldw + " " + oldh);
if (oldw == 0 || oldh == 0) return;
if (boardListener != null) {
if (h - oldh < -CHANGE_SIZE) {
Log.i("bqt", "键盘弹出" + "change" + w + " " + h + " " + oldw + " " + oldh);
boardListener.keyBoardVisable(Math.abs(h - oldh));
}
if (h - oldh > CHANGE_SIZE) {
Log.i("bqt", "键盘结束" + "change" + w + " " + h + " " + oldw + " " + oldh);
boardListener.keyBoardInvisable(Math.abs(h - oldh));
}
}
}
public interface SoftkeyBoardListener {
public void keyBoardVisable(int move);
public void keyBoardInvisable(int move);
}
private SoftkeyBoardListener boardListener;
public void setSoftKeyBoardListener(SoftkeyBoardListener boardListener) {
this.boardListener = boardListener;
}
}
x
1
public class AdjustSizeRelativeLayout extends RelativeLayout {
2
public AdjustSizeRelativeLayout(Context context) {
3
super(context);
4
}
5
6
public AdjustSizeRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
7
super(context, attrs, defStyle);
8
}
9
10
public AdjustSizeRelativeLayout(Context context, AttributeSet attrs) {
11
super(context, attrs);
12
}
13
14
private static final int CHANGE_SIZE = 200;
15
16
17
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
18
super.onSizeChanged(w, h, oldw, oldh);
19
Log.i("bqt", "【onSizeChanged】" + w + " " + h + " " + oldw + " " + oldh);
20
if (oldw == 0 || oldh == 0) return;
21
22
if (boardListener != null) {
23
if (h - oldh < -CHANGE_SIZE) {
24
Log.i("bqt", "键盘弹出" + "change" + w + " " + h + " " + oldw + " " + oldh);
25
boardListener.keyBoardVisable(Math.abs(h - oldh));
26
}
27
if (h - oldh > CHANGE_SIZE) {
28
Log.i("bqt", "键盘结束" + "change" + w + " " + h + " " + oldw + " " + oldh);
29
boardListener.keyBoardInvisable(Math.abs(h - oldh));
30
}
31
}
32
}
33
34
public interface SoftkeyBoardListener {
35
public void keyBoardVisable(int move);
36
37
public void keyBoardInvisable(int move);
38
}
39
40
private SoftkeyBoardListener boardListener;
41
42
public void setSoftKeyBoardListener(SoftkeyBoardListener boardListener) {
43
this.boardListener = boardListener;
44
}
45
}
布局
<?xml version="1.0" encoding="utf-8"?>
<com.bqt.test.AdjustSizeRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_alignParentBottom="true"
android:hint="输入交易密码"
android:inputType="text"
android:paddingLeft="5dp"/>
</com.bqt.test.AdjustSizeRelativeLayout>
1
<?xml version="1.0" encoding="utf-8"?>
2
<com.bqt.test.AdjustSizeRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
android:id="@+id/rl_root"
4
android:layout_width="match_parent"
5
android:layout_height="match_parent">
6
7
<EditText
8
android:layout_width="match_parent"
9
android:layout_height="44dp"
10
android:layout_alignParentBottom="true"
11
android:hint="输入交易密码"
12
android:inputType="text"
13
android:paddingLeft="5dp"/>
14
15
</com.bqt.test.AdjustSizeRelativeLayout>
使用
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.edit);
AdjustSizeRelativeLayout layout = findViewById(R.id.rl_root);
layout.setSoftKeyBoardListener(new AdjustSizeRelativeLayout.SoftkeyBoardListener() {
@Override
public void keyBoardVisable(int move) {
Toast.makeText(MainActivity.this, "键盘弹起,高度:" + move, Toast.LENGTH_SHORT).show();
layout.scrollBy(0, move);
}
@Override
public void keyBoardInvisable(int move) {
Toast.makeText(MainActivity.this, "键盘隐藏,高度:" + move, Toast.LENGTH_SHORT).show();
layout.scrollBy(0, -move);
}
});
}
}
1
21
1
public class MainActivity extends Activity {
2
3
protected void onCreate(Bundle savedInstanceState) {
4
super.onCreate(savedInstanceState);
5
setContentView(R.layout.edit);
6
AdjustSizeRelativeLayout layout = findViewById(R.id.rl_root);
7
layout.setSoftKeyBoardListener(new AdjustSizeRelativeLayout.SoftkeyBoardListener() {
8
9
public void keyBoardVisable(int move) {
10
Toast.makeText(MainActivity.this, "键盘弹起,高度:" + move, Toast.LENGTH_SHORT).show();
11
layout.scrollBy(0, move);
12
}
13
14
15
public void keyBoardInvisable(int move) {
16
Toast.makeText(MainActivity.this, "键盘隐藏,高度:" + move, Toast.LENGTH_SHORT).show();
17
layout.scrollBy(0, -move);
18
}
19
});
20
}
21
}
添加 OnLayoutChangeListener - 推荐
不要忘了设置键盘
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
1
1
1
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
使用
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.edit);
int scrollHeight = getWindowManager().getDefaultDisplay().getHeight() / 4;
findViewById(R.id.rl_root).addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
if (oldBottom != 0 && bottom != 0) {
int softInputHeight = oldBottom - bottom;//这个就是键盘高度
Log.i("bqt", "【键盘高度】" + Math.abs(softInputHeight));
if (softInputHeight > scrollHeight) {
Toast.makeText(MainActivity.this, "键盘弹起", Toast.LENGTH_SHORT).show();
v.scrollBy(0, softInputHeight);
} else if (Math.abs(softInputHeight) > scrollHeight) {
Toast.makeText(MainActivity.this, "键盘落下", Toast.LENGTH_SHORT).show();
v.scrollBy(0, softInputHeight);
}
}
});
}
}
v.scrollBy(0, softInputHeight);
1
26
1
public class MainActivity extends Activity {
2
3
protected void onCreate(Bundle savedInstanceState) {
4
super.onCreate(savedInstanceState);
5
setContentView(R.layout.edit);
6
7
int scrollHeight = getWindowManager().getDefaultDisplay().getHeight() / 4;
8
findViewById(R.id.rl_root).addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
9
if (oldBottom != 0 && bottom != 0) {
10
int softInputHeight = oldBottom - bottom;//这个就是键盘高度
11
Log.i("bqt", "【键盘高度】" + Math.abs(softInputHeight));
12
13
if (softInputHeight > scrollHeight) {
14
Toast.makeText(MainActivity.this, "键盘弹起", Toast.LENGTH_SHORT).show();
15
v.scrollBy(0, softInputHeight);
16
} else if (Math.abs(softInputHeight) > scrollHeight) {
17
Toast.makeText(MainActivity.this, "键盘落下", Toast.LENGTH_SHORT).show();
18
v.scrollBy(0, softInputHeight);
19
}
20
}
21
});
22
}
23
}
添加 OnGlobalLayoutListener - 推荐
不要忘了设置键盘
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
x
1
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
KeyboardChangeListener
public class KeyboardChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {
private static final String TAG = "bqt";
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) {
//hidden
isShow = false;
} else {
//show
keyboardHeight = mOriginHeight - currHeight;
isShow = true;
}
if (mKeyBoardListen != null) {
mKeyBoardListen.onKeyboardChange(isShow, keyboardHeight);
}
}
}
@SuppressLint("ObsoleteSdkInt")
public void destroy() {
if (mContentView != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mContentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
}
}
86
86
1
public class KeyboardChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {
2
private static final String TAG = "bqt";
3
private View mContentView;
4
private int mOriginHeight;
5
private int mPreHeight;
6
private KeyBoardListener mKeyBoardListen;
7
8
public interface KeyBoardListener {
9
/**
10
* call back
11
*
12
* @param isShow true is show else hidden
13
* @param keyboardHeight keyboard height
14
*/
15
void onKeyboardChange(boolean isShow, int keyboardHeight);
16
}
17
18
public void setKeyBoardListener(KeyBoardListener keyBoardListen) {
19
this.mKeyBoardListen = keyBoardListen;
20
}
21
22
public KeyboardChangeListener(Activity contextObj) {
23
if (contextObj == null) {
24
Log.i(TAG, "contextObj is null");
25
return;
26
}
27
mContentView = findContentView(contextObj);
28
if (mContentView != null) {
29
addContentTreeObserver();
30
}
31
}
32
33
private View findContentView(Activity contextObj) {
34
return contextObj.findViewById(android.R.id.content);
35
}
36
37
private void addContentTreeObserver() {
38
mContentView.getViewTreeObserver().addOnGlobalLayoutListener(this);
39
}
40
41
42
public void onGlobalLayout() {
43
int currHeight = mContentView.getHeight();
44
if (currHeight == 0) {
45
Log.i(TAG, "currHeight is 0");
46
return;
47
}
48
boolean hasChange = false;
49
if (mPreHeight == 0) {
50
mPreHeight = currHeight;
51
mOriginHeight = currHeight;
52
} else {
53
if (mPreHeight != currHeight) {
54
hasChange = true;
55
mPreHeight = currHeight;
56
} else {
57
hasChange = false;
58
}
59
}
60
if (hasChange) {
61
boolean isShow;
62
int keyboardHeight = 0;
63
if (mOriginHeight == currHeight) {
64
//hidden
65
isShow = false;
66
} else {
67
//show
68
keyboardHeight = mOriginHeight - currHeight;
69
isShow = true;
70
}
71
72
if (mKeyBoardListen != null) {
73
mKeyBoardListen.onKeyboardChange(isShow, keyboardHeight);
74
}
75
}
76
}
77
78
("ObsoleteSdkInt")
79
public void destroy() {
80
if (mContentView != null) {
81
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
82
mContentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
83
}
84
}
85
}
86
}
使用
public class MainActivity extends Activity {
private int keyboardHeight;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.edit);
RelativeLayout layout = findViewById(R.id.rl_root);
new KeyboardChangeListener(this).setKeyBoardListener((isShow, keyboardCurrentHeight) -> {
Log.i("bqt", "【当前键盘的高度】" + keyboardCurrentHeight);//注意,这里返回的直接是键盘的高度,键盘隐藏时高度为0
if (isShow) {
this.keyboardHeight = keyboardCurrentHeight;
Log.i("bqt", "【键盘的高度】" + keyboardHeight);
Toast.makeText(MainActivity.this, "键盘弹起", Toast.LENGTH_SHORT).show();
layout.scrollBy(0, keyboardHeight);
} else {
Toast.makeText(MainActivity.this, "键盘隐藏", Toast.LENGTH_SHORT).show();
layout.scrollBy(0, -keyboardHeight);
}
});
}
}
1
public class MainActivity extends Activity {
2
private int keyboardHeight;
3
4
protected void onCreate(Bundle savedInstanceState) {
5
super.onCreate(savedInstanceState);
6
setContentView(R.layout.edit);
7
RelativeLayout layout = findViewById(R.id.rl_root);
8
new KeyboardChangeListener(this).setKeyBoardListener((isShow, keyboardCurrentHeight) -> {
9
Log.i("bqt", "【当前键盘的高度】" + keyboardCurrentHeight);//注意,这里返回的直接是键盘的高度,键盘隐藏时高度为0
10
if (isShow) {
11
this.keyboardHeight = keyboardCurrentHeight;
12
Log.i("bqt", "【键盘的高度】" + keyboardHeight);
13
Toast.makeText(MainActivity.this, "键盘弹起", Toast.LENGTH_SHORT).show();
14
layout.scrollBy(0, keyboardHeight);
15
} else {
16
Toast.makeText(MainActivity.this, "键盘隐藏", Toast.LENGTH_SHORT).show();
17
layout.scrollBy(0, -keyboardHeight);
18
}
19
});
20
}
21
}
2018-5-21