关于软键盘弹出时布局调整的学习

我尽量不打错别字,用词准确,不造成阅读障碍

实际开发中会遇到的在输入框获取焦点后键盘弹出时,希望布局上移,以防止键盘遮挡了输入框下面的“确认”或“完成”按钮。这个其实很简单的,而且实现方式有多种,但是我看网上的方案写的都太模糊了,而且普适性不强,正好最近也改动了一些,就写一写。

我就以两种形式来说明。一般就这两种形式比较多,其他具体情况请适当对比和改动。

一.登录页形式

如图:

这里写图片描述

这种情况的要求一般是不允许遮挡登录按钮,希望在键盘弹出时logo缩小并且布局上移一部分。页面最下面还有第三方登录,所以修改Mainifests的方法就不太好用,Mainifests的方法就是修改Activity的windowSoftInputMode属性,后面再讲这个属性的修改方法。

这种适应屏幕的布局可以不加上ScrollView,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rl_login_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginBottom="30dp"
    android:background="#ffffff"
    android:orientation="vertical"
    android:paddingEnd="16dp"
    android:paddingStart="16dp"
    android:paddingTop="15dp">

    <TextView
        android:id="@+id/tv_register"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:text="注册"
        android:textColor="#000000" />

    <ScrollView
        android:id="@+id/sv_login"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/tv_register"
        android:fillViewport="true"
        android:scrollbars="none">

        <RelativeLayout
            android:id="@+id/rl_login"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/iv_login_logo"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="20dp"
                android:src="@mipmap/ic_launcher_round" />

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/iv_login_logo"
                android:layout_marginTop="15dp"
                android:orientation="vertical">

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:focusable="true"
                    android:focusableInTouchMode="true">

                    <EditText
                        android:id="@+id/et_account"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:background="@null"
                        android:hint="请输入账号"
                        android:inputType="phone"
                        android:maxLength="11"
                        android:maxLines="1"
                        android:paddingBottom="15dp"
                        android:paddingTop="15dp"
                        android:textColor="#333333"
                        android:textColorHint="#cccccc"
                        android:textSize="14sp" />

                    <View
                        android:id="@+id/view_line"
                        android:layout_width="match_parent"
                        android:layout_height="1px"
                        android:layout_below="@id/et_account"
                        android:background="#999999" />
                </RelativeLayout>

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:focusable="true"
                    android:focusableInTouchMode="true">

                    <EditText
                        android:id="@+id/et_password"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:background="@null"
                        android:hint="请输入密码"
                        android:inputType="textPassword"
                        android:maxLines="1"
                        android:paddingBottom="15dp"
                        android:paddingTop="15dp"
                        android:textColor="#333333"
                        android:textColorHint="#cccccc"
                        android:textSize="14sp" />

                    <View
                        android:layout_width="match_parent"
                        android:layout_height="1px"
                        android:layout_below="@id/et_password"
                        android:background="#999999" />
                </RelativeLayout>

                <TextView
                    android:id="@+id/tv_forget_password"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="end"
                    android:layout_marginTop="15dp"
                    android:text="忘记密码"
                    android:textColor="#fd3b32"
                    android:textSize="12sp" />

                <TextView
                    android:id="@+id/tv_login"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="15dp"
                    android:background="#FF4081"
                    android:enabled="false"
                    android:gravity="center"
                    android:paddingBottom="15dp"
                    android:paddingTop="15dp"
                    android:text="登录"
                    android:textColor="#ffffff"
                    android:textSize="16sp" />
            </LinearLayout>
        </RelativeLayout>
    </ScrollView>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:layout_alignParentBottom="true"
        android:gravity="bottom">

        <ImageView
            android:id="@+id/iv_we_chat_login"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:src="@mipmap/wechat_login_page" />

        <TextView
            android:id="@+id/tv_qq_login"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:drawableBottom="@mipmap/qq_login_page"
            android:drawablePadding="15dp"
            android:gravity="center"
            android:text="第三方登录"
            android:textColor="#cccccc" />

        <ImageView
            android:id="@+id/iv_wei_bo_login"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:src="@mipmap/weibo_login_page" />

    </LinearLayout>
</RelativeLayout>

我为了写着方便所以布局有些冗余,至于NestedScrollView可不可以,我没试过,你可以试一下。

这种可以不加ScrollView等,因为你的布局是完全填充进屏幕的,并没有多出的部分,就不会触发ScrollView的滚动,所以上面布局的ScrollView是可以去掉的,对于有超出屏幕,显示不下所有布局的情况,是另外的方法,注释有。

所以代码可以如下:

private TextView login_tv;
private ScrollView login_sv;
private RelativeLayout login_rl;
private ImageView login_iv;
private boolean isKeyBordVisible = false;
private boolean isCanChange = true;

//省略OnCreate和其中数据绑定部分。

login_rl.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                //获取当前界面可视部分
                getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
                //获取屏幕的高度
                int screenHeight = getWindow().getDecorView().getRootView().getHeight();
                //此处就是用来获取键盘的高度的,在键盘没有弹出的时候此高度为0,键盘弹出的时候为一个正数
                int heightDifference = screenHeight - r.bottom;
                int up = 0;
                if (heightDifference > 200) {
                  //判断软键盘弹出,200是为了适应华为手机可以隐藏虚拟按键的情况,如荣耀6pPlus
                    if (!isKeyBordVisible) {
                        int[] location = new int[2];
                        login_tv.getLocationOnScreen(location);
                        int y = location[1];                      //获取tv上边距离屏幕顶端的距离
                        up = y - r.bottom + login_tv.getHeight(); //计算需要移动的距离
                        //控件向上滑动up像素,用于布局有超出部分的情况
//                      root_sv.smoothScrollBy(0, up); 
                        login_rl.setTranslationY(-up); //控件向上移动up像素
                        isKeyBordVisible = true;
                        if (isCanChange) {
                            zoomIn();
                            isCanChange = false;
                        }
                    }
                } else {
                  //判断软件盘未弹出,收起
                    if (!isCanChange) {
                        zoomOut();
                        isCanChange = true;
                    }
                    isKeyBordVisible = false;
                    login_rl.setTranslationY(up); //控件向下移动up像素
                }
            }
        });

//ImageView的缩小
    public void zoomIn() {
        ScaleAnimation scaleAnimation = new ScaleAnimation(1, 0.5f, 1, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        scaleAnimation.setDuration(200);
        scaleAnimation.setFillAfter(true);
        login_iv.startAnimation(scaleAnimation);
    }

//ImageView的放大
    public void zoomOut() {
        ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 1, 0.5f, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        scaleAnimation.setDuration(200);
        scaleAnimation.setFillAfter(true);
        login_iv.startAnimation(scaleAnimation);
    }

代码逻辑可以优化,各种if太繁琐,自己视情况而定,我就图个方便

效果图:

这里写图片描述

这种写法是不需要在Manifests文件里面设置activity的windowSoftInputMode属性的,比较方便,而且应该是可以适应各种屏幕情况的。
还有另外一种方式,直接使用属性动画改变logo的大小,界面自动上移,代码如下:

 public void valueAnimationIn() {
 int height = login_logo_iv.getHeight();
        ValueAnimator valueAnimator = ValueAnimator.ofInt(height, height / 2);
        valueAnimator.setDuration(200);
        valueAnimator.setStartDelay(0);
        valueAnimator.setTarget(login_logo_iv);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int current = (int) animation.getAnimatedValue();
                login_logo_iv.getLayoutParams().height = current;
                login_logo_iv.getLayoutParams().width = current;
                login_logo_iv.requestLayout();
            }
        });
        valueAnimator.start();
        }

相应的,改变ofInt()参数设置变大动画,这样代码简洁许多,且不用强制上移ScrolView、RelativeLayout等控件位置。

对于布局并没有在屏幕上显示完全,有多余的情况,就必须包含ScrollView,并只需在按断软键盘弹起并计算完应滑动的距离后使用root_sv.smoothScrollBy(0, up);即可,参考注释,up的正负值是影响滑动方向的。

效果如下:

这里写图片描述

先计算登录按钮的TextView的下边线在屏幕的位置,再计算键盘弹出后剩余可见区域的下边线的值,两者差值作为滑动或移动的距离,这样刚刚好可以显示出登录按钮。特殊情况下,如果登录页有多种登录形式,密码登录和短信登录并存,使用了viewPage切换的话,也可以计算父布局RelativeLayout或ViewPage或ScrollView的下边线在屏幕位置,总之是计算应该显示的部分的下边线在屏幕的位置。

二.聊天界面形式

这里写图片描述

如果EditText在最下面的话是会自己向上顶的,但是你也可以借助在manifest文件里设置属性来更改软键盘的弹出形式:

属性作用
adjustPan当软键盘弹出时,调整空白区域来显示软键盘,但是仍有可能遮挡部分内容。
adjustNothing当软键盘弹出时,布局不做调整。
adjustResize当软键盘弹出时,调整布局以显示软件盘,但是会把在布局最底端的控件顶起来,像上例中的QQ登录、微信登录等按钮。
adjustUnspecified不指定显示软键盘时,布局显示方式。若内容区域可滚动为adjustPan,否则为adjustResize。
stateAlwaysHidden软键盘总是隐藏。
stateAlwaysVisible软件盘总是显示。
stateHidden用户进入该页面时隐藏软件盘,防止有EditText的时候软件盘乱弹。
stateVisible用户进入该页面时显示软件盘,让用户直接输入。
stateUnchanged保存上一个Activity时软件盘显示或隐藏的状态。
stateUnspecified默认设置,系统自动选择一个状态或根据主题设置。

熟悉表格内的属性,就可以根据情况控制软键盘显示方式。如果有问题,结合第一种形式,用代码的方式加以调整就可以解决绝大部分问题了。

如有不对的地方十分欢迎指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值