android 输入法键盘弹出与否判断和输入法键盘弹出时将界面滚动到指定位置

本文章重点谈下如何实现,结合以下demo,来谈谈输入法键盘弹出与否判断和输入法键盘弹出时将界面滚动到指定位置

1、先看下demo的场景,这是个登录界面,因为界面元素比较多,导致在输入法弹出时,下面的登录按钮会将登录按钮覆盖,这是非常影响用户体验的。如果输入法弹出时,可以将登录按钮展示出来是不是会更好些

                

2、 

首先有个前提,界面元素必须在ScrollView布局里面

如果不是ScrollView,当输入法虚拟键盘弹出时,界面底部被键盘覆盖后,便无法滚动查看下面内容,也无从谈起解决办法。还有以下解决办法基于adjustResize模式下

 android:name="com.example.pullkeytotop.MainActivity"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="adjustResize|stateHidden"
3、

 3.1方法一

输入法弹出键盘时,会默认压缩界面,将输入框顶到输入法以上,此时我们可以在布局做下调整,将edittext的底部调整到想要界面滚动到的位置

利用系统默认方法,当输入法弹出,就会自动将界面滚动到指定位置。

方法一优点:实现简单

方法一缺点:部分机型、输入法不支持;通用性差,要使用的界面布局都得特别调整。

个人前期使用这种方式实现,不推荐,也就不具体展开讨论

 3.2方法二

因为界面布局基于ScrollView上,所以可以通过在输入法弹出时,将界面滚动指定距离,从而实现效果,但要实现这个方法有几个难点:

    3.2.1输入法是弹出还是收起状态

这个在android内没有提供判断方法,无法直接获取到;但是,出软键盘后必然会造成原有布局高度的减少,那么系统应该如何来处理布局的减少?我们能否在应用程序中进行自定义的控制?

软件盘的本质是什么?软键盘其实是一个Dialog、nputMethodService为我们的输入法创建了一个Dialog,并且将该Dialog的Window的某些参数(如Gravity)进行了设置,使之能够在底部或者全屏显示。当我们点击输入框时,系统对活动主窗口进行调整,从而为输入法腾出相应的空间,然后将该Dialog显示在底部,或者全屏显示。

在键盘弹出过程中,根布局调用了onMeasure,onSizeChanged和onLayout。实际上,当设置为adjustResize后,软键盘弹出时,要对主窗口布局重新进行measure和layout。所以输入法状态是可以通过变相获取到的,但是因为在activity创建时也有有布局调整,甚至在输入法的数字、英文等键盘之间切换时也会有高度差变化,暂无一个能完美判断输入法是否弹出的方法

  3.2.2  界面滚动距离问题

界面滚动要指定位置刚好在键盘之上,

通过一段时间研究,终于得出要滚动的距离计算公式,当然也可以有其他计算方法,有更好的方法可以和我

要滚动的距离=控件距屏幕顶部距离+控件高度-输入法弹出后的activity高度-通知栏高度

public static void pullKeywordTop(final Activity activity,final int lyRootID,final int vID,final int svID){
        ViewGroup ly = (ViewGroup) activity.findViewById(lyRootID);
        //获取屏幕高度,根据经验,输入法弹出高度一般在屏幕1/3到1/2之间
        final int defaultHeight = ((WindowManager)activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight();
        final int mKeyHeight = defaultHeight/4;
        ly.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right,
                                       int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                //获取根布局前后高度差
            	int height = oldBottom-bottom;
                ScrollView sv = (ScrollView)activity.findViewById(svID);
                if(height>mKeyHeight) {//当高度差大于屏幕1/4,认为是输入法弹出变动,可能会有特殊机型会失败
                	 final int lybottom = bottom;
                    sv.post(new Runnable() {//用post防止有时输入法会自动滚动覆盖我们手动滚动
                        @Override
                        public void run() {
                            ScrollView runSv = (ScrollView)activity.findViewById(svID);
                            //获取要滚动至的控件到屏幕顶部高度
                            View v = (View)activity.findViewById(vID);
                            int[] loca = new int[2];
                            v.getLocationOnScreen(loca);
                            //这种通知栏高度获取方法必须在布局构建完毕后才能生效,否则获取为0
                            Rect frame = new Rect();
                            activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
                            int statusBarHeight = frame.top;
                           // 要滚动的距离=控件距屏幕顶部距离+控件高度-输入法弹出后的activity高度-通知栏高度
                            int scrollHeight = loca[1] +  v.getHeight() - lybottom - statusBarHeight;
                            if(scrollHeight>0){
                                runSv.scrollBy(0, scrollHeight);
                            }

                        }
                    });
                }else if(-height>mKeyHeight){//当输入法收起,回滚回顶部
                    sv.scrollTo(0,0);
                }
            }
        });



    }

具体实现demo 链接


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值