adjustResize模式下ExpandaleListView中输入框焦点错乱及布局底部的导航栏被顶在键盘上方的处理
为了更好的用户体验,煎熬了许久,得到这么个解决方案。在此记录下来,以供后来者参考。
第一部分
清单文件中组件activity的android:windowSoftInputMode
属性值的含义:
【A】stateUnspecified:软键盘的状态并没有指定,系统将选择一个合适的状态或依赖于主题的设置
【B】stateUnchanged:当这个activity出现时,软键盘将一直保持在上一个activity里的状态,无论是隐藏还是显示
【C】stateHidden:用户选择activity时,软键盘总是被隐藏
【D】stateAlwaysHidden:当该Activity主窗口获取焦点时,软键盘也总是被隐藏的
【E】stateVisible:软键盘通常是可见的
【F】stateAlwaysVisible:用户选择activity时,软键盘总是显示的状态
【G】adjustUnspecified:默认设置,通常由系统自行决定是隐藏还是显示
【H】adjustResize:该Activity总是调整屏幕的大小以便留出软键盘的空间
【I】adjustPan:当前窗口的内容将自动移动以便当前焦点从不被键盘覆盖
注意:
1、当对状态栏进行沉浸式处理时,adjustResize和adjustPan模式可能会失效,此时应该给activity的根布局设置此属性:android:fitsSystemWindows="true"。
2、adjustResize模式下,要想键盘不遮挡输入框,那么就需要使用scrollview来包裹,如果editext所在的直属scrollview下面还有控件(多数时候是一个或者多个按钮),那么键盘上将会出现这些按钮,体验不好;adjustPan模式下,会将布局向上顶出屏幕,以保证输入框始终在视野范围内,所以title会被顶出,而体验差。
第二部分
对软键盘的显示和隐藏状态进行监听。目的是解决adjustResize模式下,布局下面的一些悬浮按钮显示在键盘上的问题。
DecorView decorview=getWindow().getDecorView();
onGlobalLayoutListener=new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();
decorview.getWindowVisibleDisplayFrame(rect);
displayHight = rect.bottom - rect.top;//布局当下的高度
hight = decorview.getHeight();//屏幕高度
if (displayHight > hight / 3 * 2) {
//布局当下的高度大于屏高的2/3,那么键盘处于隐藏的状态
} else {
//布局当下的高度小于等于屏高的2/3,那么键盘处于显示的状态
}
}
};
decorview.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
第三部分
当adjustResize模式下,使用到ExpandaleListView控件,且其分组展开项中包含有输入框。这时会出现诸如:输入框依旧被键盘遮挡了;遮挡的输入框没有焦点而不能输入内容;展开和收起分组时自动滚动到焦点所在位置等问题。
完整的处理方式如下:
第一步:
在ExpandaleListView控件外层套上ScorllView。
<ScrollView
android:id="@+id/sv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none">
<com.ruitukeji.bellink.view.NestedExpandaleListView
android:id="@+id/exListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:childIndicator="@null"
android:descendantFocusability="beforeDescendants"//这个属性是决定输入框能不能获取到焦点
android:divider="@null"
android:dividerHeight="0dp"
android:fastScrollEnabled="false"//这个属性是跟嵌套时滚动相关的
android:groupIndicator="@null" />
</ScrollView>
ScrollView嵌套ExpandaleListView时,需要自定义ExpandaleListView控件,如下:
public class NestedExpandaleListView extends ExpandableListView {
public NestedExpandaleListView(Context context) {
super(context);
}
public NestedExpandaleListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NestedExpandaleListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public NestedExpandaleListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
//将重新计算的高度传递回去
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
第二步:
给ExpandaleListView控件设置展开和收起分组的监听事件
exListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
exListView.requestFocus();//将焦点从输入框夺回,避免自动滚动到输入框所在的分组。并且需要把焦点给到ExpandaleListView控件。当把焦点给到这里的v时,这里的监听事件将无法再被执行。
return false;//true:已经处理的点击事件,那么分组的张开和收起将不会执行,除非,在此句之前通过代码来操作。false:没有处理点击事件,系统自动执行展开或者收起操作。
}
});
第三步:
因为当收起键盘时,焦点还在输入框的话,那么此时点击分组进行展开或者收起操作,依旧会滚动到焦点所在位置,且顶布局顶显示。这个时候就需要我们去通过监听键盘隐藏来将焦点从输入框夺来给到ExpandaleListView控件。
注意:ExpandaleListView有输入框时,布局尽可能不去复用。必须复用时,自行进行完善。
说明:本文是以ExpandaleListView控件来作为示例的,其它控件雷同,可举一反三而得解决。
以上内容仅供参考,如有问题,烦请留言,共同提高。
鸣谢:
https://blog.csdn.net/zhuawalibai/article/details/76668047