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向上滚动,使输入框正好在输入法上方显示。

具体实现步骤如下:

  1. 定义并实现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();
            }
        }
    }
}
  1. 在主界面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 软键盘的全面解析,让你不再怕控件被遮盖!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Calvin880828

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值