http://www.2cto.com/kf/201405/298962.html
在android中,经常会和输入法的软件键盘交互。在Manifest文件里,系统给activity的一个属性-windowSoftInputMode来控制输入法的显示方式。该属性提供了Activity的window与软键盘的window交互的方式。这里的属性设置有两方面的影响:
1.软键盘的显示与隐藏。-当Activity界面成为用户的焦点时,或隐藏或显示。
2。对Activty的主window窗口进行调整。或者将Activity的window窗口调小以便为软键盘腾出空间,或者当Activity的部分window被软件盖住时,移动Activity的内容以便用户能够看到当前的焦点。
你至少要从下列属性值选取一项对其设置,要么是”state...“,要么是”adjust...“。你可以设置多个值。设置不同的属性值,要用|进行分开。比如:
下面是对属性的值的描述。
值 | 描述 |
”stateUnSpecified“ | 不指定软件的状态(显示或隐藏)。系统会根据主题中的设置来选择相应的状态。 该属性软键盘的默认设置。 |
”stateUnchnaged“ | 总是保持上次软键盘的状态。当Activity进入到最前端时,不论是它上次它是显示或隐藏,保持不变。 |
”stateHidden“ | 当用户进入目标Activity时,软键盘保持隐藏状态。这里的Activity是用户是向前进入Activity,而不是由于退出其它Activity退回到目标Activity。 |
”stateVisible“ | 只有条件合适(当用户前进进入到Activity的主window),就会显示键盘 |
”stateAlawaysVisible“ | 当用户选择进入目标Activity时,软键盘被设置为可见的。这里的Activity是用户向前进入的Activity,而不是由于退出其它Activity而回到目标Activity |
"adjustUnspecified" | 不指定是否去调整Activity的界面。或者调整Activity窗口的大小以便为软键盘腾出空间或者移动窗口的内容来屏幕上当前的焦点可见。系统会自动选择其中一种模式,这依赖于窗口是包含可以滑动其内容的view.如有这样的视图,窗口的大小就会被调整。在这样的假定的情况下,很小的滑动就可以使用窗口的内容可见。 该属性是主windowr默认设置。 |
”adjustResize“ | Activity的窗口总是被调整其大小以便为软键盘腾出空间。 |
”adjustPan“ | Activity的主窗口不会被调整其大小以便为软键盘腾出空间。相反,窗口的内容会被自动移动以便当前的焦点不会被软键盘遮住,用户可以总是看到他输入的内容。这个值一般用于用户很少想调整窗口的大小的情况下,因为用户可能需要关闭软键盘来与窗口的其它部分进行交互。 |
从上面系统的描述了解了系统在处理两个交互时都显示Activity和软键盘都是看作window窗口来处理的。
很多的时候,我们都希望能够监听到软件键盘的显示与关闭状态,比如下图的情况,
你有一个登录界面是这样设计的
你希望登录时它是这样的,
你不甘心,你将adjustResize修改成adjustPan,结果是这样的
没有办法,只有靠我们自己来监听键盘的显示或隐藏来动态改变布局。现在的问题是怎么监听到键盘的动态改变呢,系统并没有提供相应的方法,我们可以通过两种方法来实现。
1.在adjustResize属性下,activity的窗口大小会发生改变,而窗口中的layout的大小也必然后会发生改变。当view大小发生改变时,必然会引起onSizeChanged(int, int, int, int)的回调。所以可能自定义一个Layout,来监测onSizeChanged()函数的回调,然后在其中的作相应的处理。这个方法也是网上传的最多的方法。
2.借助ViewTreeOberserver类。ViewTreeOberserver可以用来注册一个监听器,它能监听view树的全局变化。这些变化包括但不限于,整个View的布局,绘制传递的源头,触摸模式的变化。
第一种方法的实现:
自定义一个Layout,以RelativeLayout为例,
可以在onSizeChanged(int w, int h,int oldw,int oldh) 方法里监听界面大小的变化,然后在该方法里定义回调函数,当监听到键盘被调出时,将键盘向上推一段距离,这样将登录键显示出来。
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
package
com.example.keyboardlistener;
import
android.content.Context;
import
android.util.AttributeSet;
import
android.util.Log;
import
android.widget.RelativeLayout;
public
class
KeyboardLayout
extends
RelativeLayout {
private
onSizeChangedListener mChangedListener;
private
static
final
String TAG =
"KeyboardLayoutTAG"
;
private
boolean
mShowKeyboard =
false
;
public
KeyboardLayout(Context context, AttributeSet attrs,
int
defStyle) {
super
(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public
KeyboardLayout(Context context, AttributeSet attrs) {
super
(context, attrs);
// TODO Auto-generated constructor stub
}
public
KeyboardLayout(Context context) {
super
(context);
// TODO Auto-generated constructor stub
}
@Override
protected
void
onMeasure(
int
widthMeasureSpec,
int
heightMeasureSpec) {
// TODO Auto-generated method stub
super
.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.d(TAG,
"onMeasure-----------"
);
}
@Override
protected
void
onLayout(
boolean
changed,
int
l,
int
t,
int
r,
int
b) {
// TODO Auto-generated method stub
super
.onLayout(changed, l, t, r, b);
Log.d(TAG,
"onLayout-------------------"
);
}
@Override
protected
void
onSizeChanged(
int
w,
int
h,
int
oldw,
int
oldh) {
// TODO Auto-generated method stub
super
.onSizeChanged(w, h, oldw, oldh);
Log.d(TAG,
"--------------------------------------------------------------"
);
Log.d(TAG,
"w----"
+ w +
"\n"
+
"h-----"
+ h +
"\n"
+
"oldW-----"
+ oldw +
"\noldh----"
+ oldh);
if
(
null
!= mChangedListener &&
0
!= oldw &&
0
!= oldh) {
if
(h < oldh) {
mShowKeyboard =
true
;
}
else
{
mShowKeyboard =
false
;
}
mChangedListener.onChanged(mShowKeyboard);
Log.d(TAG,
"mShowKeyboard----- "
+ mShowKeyboard);
}
}
public
void
setOnSizeChangedListener(onSizeChangedListener listener) {
mChangedListener = listener;
}
interface
onSizeChangedListener{
void
onChanged(
boolean
showKeyboard);
}
}
|
在主Activity里创建一个Handler,当监听到布局发生变化时,通过Handler更新UI。
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
package
com.example.keyboardlistener;
import
android.app.Activity;
import
android.os.Bundle;
import
android.os.Handler;
import
android.os.Message;
import
android.util.Log;
import
android.view.ViewTreeObserver.OnPreDrawListener;
import
android.widget.Button;
import
com.example.keyboardlistener.KeyboardLayout.onSizeChangedListener;
public
class
MainActivity
extends
Activity {
private
static
final
String TAG =
"KeyboardLayoutTAG"
;
private
KeyboardLayout mRoot;
private
Button mLogin;
private
int
mLoginBottom;
private
static
final
int
KEYBOARD_SHOW =
0X10
;
private
static
final
int
KEYBOARD_HIDE =
0X20
;
private
boolean
mGetBottom =
true
;
private
Handler mHandler =
new
Handler() {
@Override
public
void
handleMessage(Message msg) {
// TODO Auto-generated method stub
super
.handleMessage(msg);
switch
(msg.what) {
case
KEYBOARD_HIDE:
mRoot.setPadding(
0
,
0
,
0
,
0
);
break
;
case
KEYBOARD_SHOW:
int
mRootBottom = mRoot.getBottom();
Log.d(TAG,
"the mLoginBottom is "
+ mLoginBottom);
mRoot.setPadding(
0
, mRootBottom - mLoginBottom,
0
,
0
);
break
;
default
:
break
;
}
}
};
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getActionBar().hide();
mRoot = (KeyboardLayout) findViewById(R.id.root_view);
mLogin = (Button) findViewById(R.id.login);
mRoot.setOnSizeChangedListener(
new
onSizeChangedListener() {
@Override
public
void
onChanged(
boolean
showKeyboard) {
// TODO Auto-generated method stub
if
(showKeyboard) {
mHandler.sendMessage(mHandler.obtainMessage(KEYBOARD_SHOW));
Log.d(TAG,
"show keyboard"
);
}
else
{
mHandler.sendMessage(mHandler.obtainMessage(KEYBOARD_HIDE));
}
}
});
mRoot.getViewTreeObserver().addOnPreDrawListener(
new
OnPreDrawListener() {
@Override
public
boolean
onPreDraw() {
// TODO Auto-generated method stub
if
(mGetBottom) {
mLoginBottom = mLogin.getBottom();
//获取登录按钮的位置信息。
}
mGetBottom =
false
;
return
true
;
}
});
}
// @Override
// public boolean onCreateOptionsMenu(Menu menu) {
// // Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.main, menu);
// return true;
// }
}
|
第二种方法的实现:
借助ViewTreeObserver类对你想监听的view添加OnGlobalLayoutListener监听器,然后在onGlobalLayout()方法里窗口的变化情况来判断键盘是否被调出来了。下面是ViewTreeObserver监听的部分的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
mRoot.getViewTreeObserver().addOnGlobalLayoutListener(
new
OnGlobalLayoutListener() {
@Override
public
void
onGlobalLayout() {
int
offset = mRoot.getRootView().getHeight() - mRoot.getHeight();
//根据视图的偏移值来判断键盘是否显示
if
(offset >
300
) {
mHandler.sendMessage(mHandler.obtainMessage(KEYBOARD_SHOW));
}
else
{
mHandler.sendMessage(mHandler.obtainMessage(KEYBOARD_HIDE));
}
}
});
|
其中Handler的具体实现同上述结构中的Handler一样。
参考文章:InputMethod