SoftInputMode用来设置软键盘的各种属性。有两种使用方式:AndroidManifest.xml文件中设置或者使用代码来设置。
// 第一种 xml清单文件中进行设置
android:windowSoftInputMode="adjustResize"
//第二种 代码设置 (在Activity对象中 可以调用 getWindow() 方法 )
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN );
windowSoftInputMode共有9个取值:
stateUnspecified,stateUnchanged,stateHidden,stateAlwaysHidden,stateVisible,stateAlwaysVisible,adjustUnspecified,adjustResize,adjustPan。
这9个取值可以划分成两大类 : StateXXX 类型,和AdjustXXX类型。
其中StateXXX类型的设置主要与软键盘的显示有关(例如 刚进入界面的时候软键盘是否显示)
而AdjustXXX类型主要涉及到软键盘弹出时候界面的调整(例如 在回复评论信息的时候我们希望软键盘弹出的时候能够把底下的EditText输入框也顶上去)。
1 stateXXX各种类型
1.1 stateUnspecified
这是系统默认的设置,系统会根据界面要求来显示软键盘,一般来说软键盘是不会自动弹出的,但是当有获得焦点的输入框有滚动需求时候就会自动弹出软键盘(例如EditText外面嵌套了ScrollView,并且EditText获得焦点)。
1.2 stateUnchanged
Unchanged就是不改变的意思,在这里的使用的一种情况就是,当前的activiy已经弹出了软键盘,当进入到新界面时候,软键盘仍然是弹出的状态。如果之前是隐藏的那么跳转的新界面软键盘也是隐藏的,保持不变(Unchanged)。
1.3 stateHidden
这种设置下,进入界面时候,软键盘都是隐藏的。
1.4 stateAlwaysHidden
这种设置可以参考1.3。 (目前还不知道两者的区别 -_ -! )
1.5 stateVisible
在一般启动情况下软键盘都会弹出(即使没有EditText)
1.6 stateAlwaysVisible
这个属性与1.5类似,不过有一些小区别,设置为stateVisible时候,如果从一个没有软键盘弹出的界面返回到当前界面时候是不会弹出软键盘的,但是设置为stateAlwaysVisible模式,即使返回之前的那个界面没有软键盘弹出,退回到当前界面的时候软键盘也是会弹起的,这也就是 AlwaysVisible 。
2 adjustXXX各种类型
之前的stateXXX属性都是跟软键盘显示隐藏相关的,下面这部分介绍的adjustXXX相关属性是跟软键盘弹起后界面调整相关的。
2.1 adjustUnspecified
这是系统默认的设置,系统会根据界面选择不同的模式。如果界面里面有可以滚动的控件,比如ScrowView,系统会减小可以滚动的界面的大小,从而保证即使软键盘显示出来了,也能够看到所有的内容。如果布局里面没有滚动的控件,那么软键盘可能就会盖住一些内容。
2.2 adjustResize
这是比较常用的用来调整输入框位置的属性,一般设置为这个属性就可以实现底部输入框被顶上去的效果。
这是由于软键盘是一个Dialog,也就是一个Window,Window可以说是View的一个容器,我们自己编写的布局文件所生成的View都是在与Activity绑定的那个Window之中,当软键盘弹出的时候,整个屏幕就被切分成了两部分,上面的View布局和下面的软键盘,这时候上面的根View会调整自己的大小(压缩自己)来适应这种变化,之后会从View的根部重新请求测量、布局、绘制。这时候软键盘的上面就成了新的底部,输入框在软键盘上面重新绘制自己,直观上就变成了输入框被软键盘给顶上去了。
2.3 adajustPan
这种模式与adajustResize的区别就在于视图View不会重新调整自己的高度,而是选择向上滚动一段距离,来让下面的输入框显示出来。当然带来的问题可能就是顶部的ActionBar等View会被顶出视线外。
3 SofiInputMode属性失效问题
经常有同学会碰到设置adajustResize 、 adajustPan属性设置失效的问题,特别是在全屏模式下或者有WebView的情况下。这个据说是一个老太太裹脚布般的大Bug.....,坑了无数的人。 目前网上比较流行的一个处理方法就是通过类AndroidBug5497Workaround来处理。如下
public class AndroidBug5497Workaround {
public static void assistActivity (Activity activity , OnSoftKeyBoardListener l) {
new AndroidBug5497Workaround(activity,l);
}
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private OnSoftKeyBoardListener listener;
private AndroidBug5497Workaround(Activity activity , OnSoftKeyBoardListener l) {
this.listener=l;
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
possiblyResizeChildOfContent();
}
});
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent() {
int usableHeightNow = computeUsableHeight();
View root=mChildOfContent.getRootView();
int usableHeightSansKeyboard = root.getHeight();
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
int offset=usableHeightNow - usableHeightPrevious;
if ( Math.abs(offset) > usableHeightSansKeyboard /4 ) {
Log.e("BBB","root Height: " +usableHeightSansKeyboard +" heightDifference: "+heightDifference);
boolean visible;
if (offset < 0) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightNow;
visible=true;
Log.e("BBB","usableHeightNow");
} else {
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightSansKeyboard;
visible=false;
Log.e("BBB","use root height");
}
Log.e("BBB",mChildOfContent.getClass().getSimpleName()+" requestLayout()");
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
listener.onSoftKeyBoardVisibleChanged(visible);
}
}
//60是我的状态栏高度
private int computeUsableHeight() {
Rect r = new Rect();
Log.e("BBB","getHeight: " + mChildOfContent.getHeight());
Log.e("BBB","getMeasureHeight: " + mChildOfContent.getMeasuredHeight());
mChildOfContent.getWindowVisibleDisplayFrame(r);
Log.e("BBB","computeUsableHeight: " + " bottom: "+r.bottom+" top:"+r.top+" r.bottom-r.top: "+ (r.bottom-r.top));
return (r.bottom - r.top)+60;
// return mChildOfContent.getHeight();
}
public interface OnSoftKeyBoardListener
{
void onSoftKeyBoardVisibleChanged(boolean visible);
}
}
大致的思想就是通过可视区域的变化来监听软键盘的弹出,之后设置下视图View的大小,重新请求布局绘制View。
mChildOfContent.getWindowVisibleDisplayFrame(r);
getWindowVisibleDisplayFrame(r)可以获得当前可见的区域,通过这个区域来取得当前显示出来的高度(这里注意根据自己的情况是否要加上状态栏的高度)。
通过
int offset=usableHeightNow - usableHeightPrevious;
来计算高度差,如果这个差值 大于屏幕的1/4 就说明出现了软键盘的弹出或者隐藏事件。然后重新设置视图的高度。
public interface OnSoftKeyBoardListener
{
void onSoftKeyBoardVisibleChanged(boolean visible);
}
这个一个软键盘监听器,可以使用这个监听器在软键盘弹出或者隐藏的时候做一些事情,参数就是当前软键盘是弹出还是隐藏。
一般来说这个方法是可以解决问题的,就算不好使或者界面调整有误也可以通过监听器在软键盘弹出或者隐藏的时候自己来处理View移动(或者改变大小)的逻辑来实现自己的需求。
如果软键盘的弹出隐藏都监听不到,那就没办法了,自求多福吧 ~~~~ !!
如果有其他的好的方法,希望您能分享,谢谢 ^ ^ ..