Android进阶之路 - 监听软键盘当前状态,实现布局上移

在项目开发中遇到这样一个问题,当用户输入某些数据时,我们接下来是进行数据操作,这时候为了让用户有更好的交互感,所以我们需要布局中的某一块布局进行整体上移,增加用户体验,故有了此篇文章,请往下看 ~

  • Effect(面临的问题)
    Android进阶之路 - 监听软键盘当前状态,实现布局上移_第1张图片

  • 公共注意点

1.在AndroidManifest中找到对应的activity,加入 android:windowSoftInputMode="stateHidden|adjustPan"

2.在代码中,我们需要俩个视图id,其中一个为最外层布局,另一个为要顶起的布局,其他布局方式与平常无异

第一种方式

  • Effect

Android进阶之路 - 监听软键盘当前状态,实现布局上移_第2张图片

  • 注意点

1.最外层为自定义的ScrollView ,注意设置 android:fillViewport="true",其意义在于让子布局展示完整
2.使用ScrollView 的同时要注意其只能包含一个子View,所以你需要在嵌套一层LinearLayout或者RelativeLayout
3.在 onResume 生命周期内 设置 mRootView.addOnLayoutChangeListener(this);
4.使用Runnable做延迟操作
5.主要思想在于通过键盘的弹起状态,设置对应的MarginBottom属性距离

  • 代码

SlowScrollView (这个自定义类主要作用于减缓滑动的速度,找自网上,可直接Copy):

package com.example.yongliu.keyboardrecord;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;
import android.widget.Scroller;

/**
 * @author yongliu
 *         date  2018/3/27.
 *         desc:
 */
public class SlowScrollView extends ScrollView {
    private Scroller mScroller;

    public SlowScrollView(Context context) {
        super(context);
        mScroller = new Scroller(context);
    }

    public SlowScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = new Scroller(context);
    }

    public SlowScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mScroller = new Scroller(context);
    }

    /**
     * 调用此方法滚动到目标位置  duration滚动时间
     */
    public void smoothScrollToSlow(int fx, int fy, int duration) {
        //mScroller.getFinalX();  普通view使用这种方法
        int dx = fx - getScrollX();
        //mScroller.getFinalY();
        int dy = fy - getScrollY();
        //this.setOverScrollMode(OVER_SCROLL_ALWAYS);
        smoothScrollBySlow(dx, dy, duration);
    }

    /**
     * 调用此方法设置滚动的相对偏移
     */
    public void smoothScrollBySlow(int dx, int dy, int duration) {

        //设置mScroller的滚动偏移量
        mScroller.startScroll(getScrollX(), getScrollY(), dx, dy, duration);
        //scrollView使用的方法(因为可以触摸拖动)
        //mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy, duration);  //普通view使用的方法
        //这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
        invalidate();
    }

    @Override
    public void computeScroll() {
        //先判断mScroller滚动是否完成
        if (mScroller.computeScrollOffset()) {
            //这里调用View的scrollTo()完成实际的滚动
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            //必须调用该方法,否则不一定能看到滚动效果
            postInvalidate();
        }
        super.computeScroll();
    }

    /**
     * 滑动事件,这是控制手指滑动的惯性速度
     */
    @Override
    public void fling(int velocityY) {
        super.fling(velocityY / 4);
    }
}

MainActivity :

package com.example.yongliu.keyboardrecord;

import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity implements View.OnLayoutChangeListener {

    private LinearLayout mOutView;
    private SlowScrollView mRootView;
    private int screenHeight;
    private int keyHeight;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRootView = findViewById(R.id.root_view);
        mOutView = findViewById(R.id.ll_out_view);

        //获取屏幕高度
        screenHeight = getWindowManager().getDefaultDisplay().getHeight();
        //阀值设置为屏幕高度的1/3
        keyHeight = screenHeight / 3;
    }

    @Override
    protected void onResume() {
        super.onResume();
        mRootView.addOnLayoutChangeListener(this);
    }

    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        //获取View可见区域的bottom
        Rect rect = new Rect();
        this.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);

        if (bottom != 0 && oldBottom != 0 && bottom - rect.bottom <= 0) {
            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mOutView.getLayoutParams();
            params.bottomMargin = 2;
            mOutView.setLayoutParams(params);
            Log.e("tag", "收起");
        } else {
            Handler handler = new Handler();
            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mOutView.getLayoutParams();
            params.bottomMargin = keyHeight + keyHeight / 2;
            mOutView.setLayoutParams(params);
            //缓慢移动,防止太快造成交互体验差的感觉
            handler.postDelayed(runnable, 100);
            Log.e("tag", "弹出");
        }
    }


    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            // 改变滚动条的位置
            mRootView.smoothScrollToSlow(0, keyHeight, 100);
        }
    };
}

MainActivity Xml :


<com.example.yongliu.keyboardrecord.SlowScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff"
    android:fillViewport="true"
    android:orientation="vertical"
    android:scrollbars="none"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >

        <ImageView
            android:id="@+id/iv_icon"
            android:layout_width="match_parent"
            android:layout_height="240dp"
            android:layout_centerInParent="true"
            android:layout_gravity="center"
            />

        <LinearLayout
            android:id="@+id/ll_out_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            >

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:orientation="vertical"
                android:paddingBottom="5dp">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="45dp"
                    android:background="#fff"
                    android:orientation="horizontal"
                    >

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_marginLeft="45dp"
                        android:gravity="center"
                        android:text="手机号:"
                        android:textColor="#363636"
                        android:textSize="16sp"/>

                    <EditText
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginLeft="15dp"
                        android:layout_weight="1"
                        android:background="@null"
                        android:gravity="center_vertical"
                        android:hint="请输入你的手机号"
                        android:inputType="number"
                        android:maxLength="11"
                        android:singleLine="true"
                        android:textSize="16sp"/>

                LinearLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="1dp"
                    android:layout_marginLeft="45dp"
                    android:layout_marginRight="45dp"
                    android:background="#363636"/>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="45dp"
                    android:background="#fff"
                    android:orientation="horizontal"
                    >

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_marginLeft="45dp"
                        android:gravity="center"
                        android:text="密码:"
                        android:textColor="#363636"
                        android:textSize="16sp"/>

                    <EditText
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginLeft="30dp"
                        android:layout_weight="1"
                        android:background="@null"
                        android:gravity="center_vertical"
                        android:hint="请输入你的密码"
                        android:inputType="number"
                        android:maxLength="11"
                        android:singleLine="true"
                        android:textSize="16sp"/>

                LinearLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="1dp"
                    android:layout_marginLeft="45dp"
                    android:layout_marginRight="45dp"
                    android:layout_marginTop="2dp"
                    android:background="#363636"/>

            LinearLayout>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:layout_marginTop="10dp"
                android:gravity="center"
                android:text="登录"
                android:textSize="14sp"/>
        LinearLayout>
    LinearLayout>
com.example.yongliu.keyboardrecord.SlowScrollView>


第二种方式 (相比第一种方式,这种方式显得更自然一些~):

  • Effect

Android进阶之路 - 监听软键盘当前状态,实现布局上移_第3张图片
- 注意点

这里在使用中发现了一个bug,如果有视图在我们获焦或者失焦的时候,有触发View.Gone 或者 View .Visible 属性的话,键盘弹起功能会失效,所以这里如果需要隐藏某一个视图的话,我们就用View . Invisible

MainActivity :

package com.example.yongliu.keyboardrecord;

import android.graphics.Rect;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
// implements View.OnLayoutChangeListener {
public class MainActivity extends AppCompatActivity{

    private LinearLayout mOutView;
    private LinearLayout mRootView;
    //设置一个默认值
    private int recordVisibleRec = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //最外层布局
        mRootView = findViewById(R.id.root_view);
        //想要顶起的布局块
        mOutView = findViewById(R.id.ll_out_view);
        controlKeyboardLayout(mRootView, mOutView);
    }


    /**
     * @param root 最外层布局,需要调整的布局
     * @param scrollToView 被键盘遮挡的scrollToView,滚动root,使scrollToView在root可视区域的底部
     */

    private void controlKeyboardLayout(final View root, final View scrollToView) {
        root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect rect = new Rect();
                //获取root在窗体的可视区域
                root.getWindowVisibleDisplayFrame(rect);
                //获取root在窗体的不可视区域高度(被其他View遮挡的区域高度)
                int rootInvisibleHeight = root.getRootView().getHeight() - rect.bottom;
                if (Math.abs(rootInvisibleHeight - recordVisibleRec) > 200) {
                    //若不可视区域高度大于200,则键盘显示
                    if (rootInvisibleHeight > 200) {
                        int[] location = new int[2];
                        //获取scrollToView在窗体的坐标
                        scrollToView.getLocationInWindow(location);
                        //计算root滚动高度,使scrollToView在可见区域
                        int srollHeight = (location[1] + scrollToView.getHeight()) - rect.bottom;
                        srollHeight = srollHeight < 0 ? 0 : srollHeight;
                        root.scrollTo(0, srollHeight);
                    } else {
                        //键盘隐藏
                        root.scrollTo(0, 0);
                    }
                }
                recordVisibleRec = rootInvisibleHeight;
            }
        });
    }
}

MainActivity Xml :


<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff"
    android:fillViewport="true"
    android:orientation="vertical"
    android:scrollbars="none"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >

        <ImageView
            android:id="@+id/iv_icon"
            android:layout_width="match_parent"
            android:layout_height="240dp"
            android:layout_centerInParent="true"
            android:layout_gravity="center"
            />

        <LinearLayout
            android:id="@+id/ll_out_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            >
            

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:orientation="vertical"
                android:paddingBottom="5dp">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="45dp"
                    android:background="#fff"
                    android:orientation="horizontal"
                    >

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_marginLeft="45dp"
                        android:gravity="center"
                        android:text="手机号:"
                        android:textColor="#363636"
                        android:textSize="16sp"/>

                    <EditText
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginLeft="15dp"
                        android:layout_weight="1"
                        android:background="@null"
                        android:gravity="center_vertical"
                        android:hint="请输入你的手机号"
                        android:inputType="number"
                        android:maxLength="11"
                        android:singleLine="true"
                        android:textSize="16sp"/>

                LinearLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="1dp"
                    android:layout_marginLeft="45dp"
                    android:layout_marginRight="45dp"
                    android:background="#363636"/>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="45dp"
                    android:background="#fff"
                    android:orientation="horizontal"
                    >

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_marginLeft="45dp"
                        android:gravity="center"
                        android:text="密码:"
                        android:textColor="#363636"
                        android:textSize="16sp"/>

                    <EditText
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginLeft="30dp"
                        android:layout_weight="1"
                        android:background="@null"
                        android:gravity="center_vertical"
                        android:hint="请输入你的密码"
                        android:inputType="number"
                        android:maxLength="11"
                        android:singleLine="true"
                        android:textSize="16sp"/>

                LinearLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="1dp"
                    android:layout_marginLeft="45dp"
                    android:layout_marginRight="45dp"
                    android:layout_marginTop="2dp"
                    android:background="#363636"/>

            LinearLayout>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:layout_marginTop="10dp"
                android:gravity="center"
                android:text="登录"
                android:textSize="14sp"/>
        LinearLayout>
    LinearLayout>
LinearLayout>

你可能感兴趣的:(#,项目开发知识点归纳)