Android软键盘遮挡EditText问题
最近在调试App过程遇到软件盘遮挡EditText的问题,特记录下问题的解决过程
在4.4版本上,如果EditText设置了gravity=“center|right”
其中之一且同时设置android:windowSoftInputMode="stateHidden|adjustPan"
,就会导致屏幕底部的EditText连续点击弹出键盘时,从第二次开会一直遮挡住EditText。在5.0+版本上不存在该问题,这可能是早期版本的Bug。
输入法的行为还与状态栏的状态有关联,比如说沉浸式、全屏及是否透明。
正常情况下,系统UI会占用app一些空间,例如状态栏、键盘、导航栏等,也就是说我们的app UI不会出现在系统UI之下,但从测试结果来看,为了占用状态栏空间或全屏,设置了上面的一些属性后,就会被系统UI覆盖。
为了规避不同系统版本以及系统状态差异造成的软件盘遮挡控件问题,需要一种统一的解决思路。这里给出一种思路:将UI界面设置为adjustPan
, 通过监测输入法的弹出及隐藏来动态调整UI 的rootView的位置,如果输入法弹出时,焦点View(一般是EditText)在输入法上方显示,那么不做处理,如果输入法弹出时,焦点View被输入法遮挡,那么就rootView向上滚动,使输入框正好在输入法上方显示。
具体实现步骤如下:
- 定义并实现
SoftKeyboardManager
管理类,用于监听SoftKeyboard的弹出与隐藏状态,并通过接口方法通知出去。
界面UI状态的变化通过ViewTreeObserver.OnGlobalLayoutListener
接口来监听
public class SoftKeyboardManager implements ViewTreeObserver.OnGlobalLayoutListener{
public static final boolean DEBUG = false;
public interface SoftKeyboardStateListener {
void onSoftKeyboardOpened(int keyboardHeightInPx);
void onSoftKeyboardClosed();
}
private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();
private final View activityRootView;
private int lastSoftKeyboardHeightInPx;
private boolean isSoftKeyboardOpened;
public SoftKeyboardManager(View activityRootView) {
this(activityRootView, false);
}
public SoftKeyboardManager(View activityRootView, boolean isSoftKeyboardOpened) {
this.activityRootView = activityRootView;
this.isSoftKeyboardOpened = isSoftKeyboardOpened;
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
public void onGlobalLayout() {
final Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (DEBUG){
Log.d("SoftKeyboardStateHelper", "heightDiff:" + heightDiff);
}
if (!isSoftKeyboardOpened && heightDiff > 500) { // if more than 100 pixels, its probably a keyboard...
isSoftKeyboardOpened = true;
notifyOnSoftKeyboardOpened(heightDiff);
//if (isSoftKeyboardOpened && heightDiff < 100)
} else if (isSoftKeyboardOpened && heightDiff < 500) {
isSoftKeyboardOpened = false;
notifyOnSoftKeyboardClosed();
}
}
public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {
this.isSoftKeyboardOpened = isSoftKeyboardOpened;
}
public boolean isSoftKeyboardOpened() {
return isSoftKeyboardOpened;
}
/**
* Default value is zero (0)
*
* @return last saved keyboard height in px
*/
public int getLastSoftKeyboardHeightInPx() {
return lastSoftKeyboardHeightInPx;
}
public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
listeners.add(listener);
}
public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
listeners.remove(listener);
}
public void dispose(){
activityRootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {
this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;
for (SoftKeyboardStateListener listener : listeners) {
if (listener != null) {
listener.onSoftKeyboardOpened(keyboardHeightInPx);
}
}
}
private void notifyOnSoftKeyboardClosed() {
for (SoftKeyboardStateListener listener : listeners) {
if (listener != null) {
listener.onSoftKeyboardClosed();
}
}
}
}
- 在主界面Activity或者Fragment中注册监听并做rootView的平移出来。
public class BaseFrameActivity extends FragmentActivity implements SoftKeyboardManager.SoftKeyboardStateListener{
private SoftKeyboardManager softKeyboardManager;
protected LinearLayout rootLl;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.root_container);
rootLl = (LinearLayout)findViewById(R.id.root_rl);
softKeyboardManager = new SoftKeyboardManager(rootLl);
softKeyboardManager.addSoftKeyboardStateListener(this);
......
}
@Override
protected void onDestroy() {
super.onDestroy();
softKeyboardManager.removeSoftKeyboardStateListener(this);
softKeyboardManager.dispose();
}
@Override
public void onSoftKeyboardOpened(int keyboardHeightInPx) {
if (SoftKeyboardManager.DEBUG){
Log.d(TAG, "keyboardOpened, keyboardHeightInPx = "+keyboardHeightInPx);
}
Rect rect = new Rect();
//获取root在窗体的可视区域
rootLl.getWindowVisibleDisplayFrame(rect);
//获取root在窗体的不可视区域高度(被其他View遮挡的区域高度)
int rootInvisibleHeight = rootLl.getRootView().getHeight() - rect.bottom;
//若不可视区域高度大于100,则键盘显示
if (rootInvisibleHeight > 100) {
int[] location = new int[2];
//获取focusedView在窗体的坐标
View focusedView = getCurrentFocus();
if (focusedView instanceof EditText){
focusedView.getLocationInWindow(location);
int focusedViewPosY = location[1] + focusedView.getHeight();
if (SoftKeyboardManager.DEBUG){
Log.d(TAG, "rect.bottom= "+rect.bottom+", focusedViewPosY = "+focusedViewPosY);
Log.i(TAG, "focused view need scroll up or down");
}
int srollHeight = focusedViewPosY - rect.bottom;
if (SoftKeyboardManager.DEBUG){
Log.i(TAG, "srollHeight = "+srollHeight);
}
if (srollHeight>0) {//焦点被输入法遮挡,View向上滚动
rootLl.scrollTo(0, srollHeight);
}
}
}
}
@Override
public void onSoftKeyboardClosed() {
if (SoftKeyboardManager.DEBUG){
Log.d(TAG, "keyboardClosed ");
}
//输入法退出,root滚动到初始位置
rootLl.scrollTo(0, 0);
}
}
参考文献
softInputMode设置成adjustPan,键盘第二次弹出时会遮挡输入框
键盘弹起引起的Pannel布局发送变化问题解决
Android 软键盘的全面解析,让你不再怕控件被遮盖!
上一篇: 一老汉人养
下一篇: 超速职员看来爆笑不多
推荐阅读
-
DownEditTextView【自定义Edittext对Android 软键盘向下的监听】
-
Android 设置Edittext获取焦点并弹出软键盘
-
js解决软键盘遮挡输入框的问题分享
-
AppCompatActivity 去掉标题栏及EditText弹出软键盘遮住输入框问题
-
android9.0长按EditText编辑框报错闪退问题
-
Android开发:在EditText中关闭软键盘
-
Android 软键盘在有scollview,纵向viewpager+recyclview实现列表,或者recyclview, 把布局顶上去的问题,保证背景不会发生变化
-
Android Studio 弹出下拉框遮挡住spinner控件本身问题
-
ios软键盘在input聚集时遮挡住输入框的问题
-
android沉浸式状态栏下,键盘遮挡输入框问题