最佳解决输入法挡住EditText的方案

开发中,经常会遇到键盘挡住输入框的情况,比如登录界面或注册界面,弹出的软键盘把登录或注册按钮挡住了,用户必须把软键盘收起,才能点击相应按钮,这样的用户体验非常不好。像微信则直接把登录按钮做在输入框的上面,但有很多情况下,这经常满足不了需求。同时如果输入框特别多的情况下,点击输入时,当前输入框没被挡住,但是当前输入框下面的输入框却无法获取焦点,必须先把键盘收起,再去获取下面输入框焦点,这样用户体验也非常不好,那有什么办法呢?
系统的adjustResize和adjustPan有什么区别,他们使用时的注意事项,有什么系统要求及蔽端呢?

下面直接说一下我用的方法:很简洁很粗暴。
因为在我自己的项目里。

1.修改AndroidManifest.xml文件

在AndroidManifest.xml中对应的Activity配置:android:windowSoftInputMode="stateVisible|adjustResize"
这些完全是没有用滴。包括之前的android也设置过了。完全没有效果。所以丢到了我的身上。

下面给大家贴出一下工具类 new到activity直接简单粗暴到解决问题

/**

  • 解决键盘档住输入框

  • Created by SmileXie on 2017/4/3.
    */

     public class SoftHideKeyBoardUtil {
    public static void assistActivity (Activity activity) {
     new SoftHideKeyBoardUtil(activity);
    }
    private View mChildOfContent;
    private int usableHeightPrevious;
    private FrameLayout.LayoutParams frameLayoutParams;
    //为适应华为小米等手机键盘上方出现黑条或不适配
    private int contentHeight;//获取setContentView本来view的高度
    private boolean isfirst = true;//只用获取一次
    private  int statusBarHeight;//状态栏高度
    private SoftHideKeyBoardUtil(Activity activity) {
    //1、找到Activity的最外层布局控件,它其实是一个DecorView,它所用的控件就是FrameLayout
     FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
     //2、获取到setContentView放进去的View
     mChildOfContent = content.getChildAt(0);
     //3、给Activity的xml布局设置View树监听,当布局有变化,如键盘弹出或收起时,都会回调此监听  
       mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
     //4、软键盘弹起会使GlobalLayout发生变化
         public void onGlobalLayout() {
         if (isfirst) {
                 contentHeight = mChildOfContent.getHeight();//兼容华为等机型
                 isfirst = false;
             }
             //5、当前布局发生变化时,对Activity的xml布局进行重绘
             possiblyResizeChildOfContent();
         }
     });
     //6、获取到Activity的xml布局的放置参数
     frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
     }
    
    // 获取界面可用高度,如果软键盘弹起后,Activity的xml布局可用高度需要减 
    去键盘高度  
     private void possiblyResizeChildOfContent() {
     //1、获取当前界面可用高度,键盘弹起后,当前界面可用布局会减少键盘的高度
     int usableHeightNow = computeUsableHeight();
     //2、如果当前可用高度和原始值不一样
     if (usableHeightNow != usableHeightPrevious) {
         //3、获取Activity中xml中布局在当前界面显示的高度
         int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
         //4、Activity中xml布局的高度-当前可用高度
         int heightDifference = usableHeightSansKeyboard - usableHeightNow;
         //5、高度差大于屏幕1/4时,说明键盘弹出
         if (heightDifference > (usableHeightSansKeyboard/4)) {
             // 6、键盘弹出了,Activity的xml布局高度应当减去键盘高度
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
                 frameLayoutParams.height = usableHeightSansKeyboard - heightDifference + statusBarHeight;
             } else {
                 frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
             }
         } else {
             frameLayoutParams.height = contentHeight;
         }
         //7、 重绘Activity的xml布局
         mChildOfContent.requestLayout();
         usableHeightPrevious = usableHeightNow;
     }
     }
    private int computeUsableHeight() {
     Rect r = new Rect();
     mChildOfContent.getWindowVisibleDisplayFrame(r);
     // 全屏模式下:直接返回r.bottom,r.top其实是状态栏的高度
     return (r.bottom - r.top);
     }
    }
    

3它的实现原理主要是:

(1) 找到Activity的最外层布局控件,我们知道所有的Activity都是DecorView,它就是一个FrameLayout控件,该控件id是系统写死叫R.id.content,就是我们setContentView时,把相应的View放在此FrameLayout控件里

FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);

所以content.getChildAt(0)获取到的mChildOfContent,也就是我们用setContentView放进去的View。
(2) 给我们的Activity的xml布局View设置一个Listener监听

    mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener({ 
    possiblyResizeChildOfContent();

});

View.getViewTreeObserver()可以获取一个ViewTreeObserver对象——它是一个观察者,用以监听当前View树所发生的变化。这里所注册的addOnGlobalLayoutListener,就是会在当前的View树的全局布局(GlobalLayout)发生变化、或者其中的View可视状态有变化时,进行通知回调。『软键盘弹出/隐 』都能监听到。
(3) 获取当前界面可用高度

private int computeUsableHeight() {
Rect rect = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(rect);
// rect.top其实是状态栏的高度,如果是全屏主题,直接 return rect.bottom就可以了
return (rect.bottom - rect.top);
}
5699111-9d1d9567db08f19d.png
image.png

(4) 重设高度, 我们计算出的可用高度,是目前在视觉效果上能看到的界面高度。但当前界面的实际高度是比可用高度要多出一个软键盘的距离的。

具体实现代码见demo中的TransStatusbarWisthAssistActivity类。

注意:如果既使用了沉浸式状态栏,又加了fitSystetemWindow=true属性,就需要在AndroidMainfest.xml注册Activity的地方添加上以下属性。因为你两种都用,系统不知道用哪种了。fitSystetemWindow已经有resize屏幕的作用。

android:windowSoftInputMode="stateHidden|adjustPan"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值