软件盘WindowsSoftInputMode遇到的问题

问题场景

  1. 业务需求:弹出键盘时,固定标题栏,并且图片和编辑框同时变更为原大小的1/2,获取焦点。
    在这里插入图片描述
    原本用的是adjustPan,获取焦点时,会挤出标题栏和滚动页面。与需求大相径庭。
  2. 使用 adjustResize 后,一点编辑框,全部页面会跳到键盘下面,被键盘遮挡。

WindowsSoftInputMode 参数

定义键盘是否弹出的参数:

  • stateUnspecified:界面没有设置"android:windowSoftInputMode"时的状态.这个状态是弹出有EditText的界面时时不弹出软键盘的,当EditText获取焦点的时候弹出软件盘,用到时才弹

  • stateUnchanged:状态不改变,意思就是和上一个界面相同,上一个界面弹出软键盘,跳转到这个界面时,软键盘也是弹出状态.

  • stateHidden:除了从上一个页面返回时,沿用上一个页面,其他情况都隐藏

  • stateAlwaysHidden:一直隐藏

  • stateVisible:除了从上一个页面返回时,沿用上一个页面,其他情况都显示

  • stateAlwaysVisible:一直显示键盘

  • 完美解决android软键盘挡住输入框方法,还不顶标题栏
    ——这篇文章很重要,完结解决了我的问题

  • Android-软键盘一招搞定(原理篇)
    在这里插入图片描述
    在这里插入图片描述
    我个人理解是:

  • adjustPan 会移动整个页面,以让Edit显示,并不会管上面的内容是什么,它主打一个不改变原有页面,不做任何自以为是的修饰。
    在这里插入图片描述

  • adjustResize 我的理解是 adjustResize 比较自恋,它会监听键盘的高度,算出当前APP可视高度,再重新调整布局。

    • 但是,人家也只会对能调的进行调整,比如 wrap_content 那种,可以挤一挤的,就挤一挤。
    • 尤其是对于 ScrollView ,或者 ConstaintLayout 这种约束布局,它会调整当前大小,而不会动标题,以及一些固定大小的View。
    • 如果整个布局都写死了高度,Edit 逃无可逃,那点击了 Edit 它也确实逃无可逃,它会逃到键盘下面,消失不见(如果本来就被遮挡的话)
    • 一般也会倾向于用 adjustResize ,在AndroidManifest.xml 的对应activity里设置 WindosSoftInputMode值。
  • adjustNothing 就是什么都不干咯。

键盘显示监听

对于一些要监听键盘是否要显示的场景,以及要在原生键盘上,设置功能键的需求,如上面这个完成键,该怎么做呢?
在这里插入图片描述

  • 监听整个页面的DecorView
  • 记录可视高度
        mViewRoot = getActivity().getWindow().getDecorView();
        mViewRoot.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
            Rect rect = new Rect();
            mViewRoot.getWindowVisibleDisplayFrame(rect);
            mPresenter.handleKeyboard(rect.height());
        });

对可视高度变化进行判断,对于键盘显示的场景做出处理

    @Override
    public void handleKeyboard(final int visibleHeight) {
        if(mVisibleHeight <= 0) {
            mVisibleHeight = visibleHeight;
            Logger.d(TAG, "handleKeyboard()=>设置可见高度,mVisibleHeight=" + mVisibleHeight);
        } else {
            if (mVisibleHeight == visibleHeight) {
                Logger.d(TAG, "handleKeyboard()=>键盘无变化,mVisibleHeight=" + mVisibleHeight);
                return;
            }
            if (mVisibleHeight - visibleHeight > 200) {
                mVisibleHeight = visibleHeight;
                Logger.d(TAG, "handleKeyboard()=>显示键盘,mVisibleHeight=" + mVisibleHeight);
                return;
            }
            if (visibleHeight - mVisibleHeight > 200) {
                mView.hideKeyboard();
                mVisibleHeight = visibleHeight;
                Logger.d(TAG, "handleKeyboard()=>隐藏键盘,mVisibleHeight=" + mVisibleHeight);
            }
        }
    }

键盘上加工具栏

其实也是利用了 adjustResize 的属性,把工具栏放在布局最底部,当显示键盘的时候也显示工具栏,由于会重新布局,这样工具栏就被放在了键盘上面。
这是一个举一反三的过程。

键盘按钮自定义

  • 系统键盘上有很多键,有换行/完成/下一个等等,可以自定义这些键盘。
editText.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
	if (keyCode == KeyEvent.KEYCODE_BACK) {
		if (listener != null) {
		// 可添加抛出收起事件代码
			}
			return true;
		}
		return false;
	}
});
  • 监听点击软键盘外部,设置事件
@Override
public boolean onTouchEvent(MotionEvent event) {
	if (indexOfChild(editText) > -1) {
		// 可添加抛出收起事件代码
		}
	return super.onTouchEvent(event);
	}

fitsSystemWindows 与键盘的关联

再学一遍android:fitsSystemWindows属性
解决业务场景的第二个问题,点击键盘时,所有页面错位,跳到了键盘下面。
这是因为 fitsSystemWindows 设定了是否为沉浸式导航栏:

  • 如果 android:fitsSystemWindows=“true” 说明不需要沉浸式导航栏,正常显示状态栏。
    • 因为最原始的View是全局的,没有区分什么状态栏。
    • 如果不需要沉浸式,那需要在写顶部 View 的时候自动位移一个状态栏。使得 top 位的 View 都是在状态栏之下的。
  • 如果是 false ,就说明是沉浸式导航栏,再写顶部 view 就会和状态栏覆盖。

完整代码

这是做Demo用到的代码,主要看ScrollView和软键盘的适配。
layout_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:fitsSystemWindows="false">

    <ScrollView
        android:id="@+id/scrollview"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintVertical_weight="1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/edit"
        android:layout_marginBottom="10dp">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recyclerview"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scrollbars="vertical"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent">

            </androidx.recyclerview.widget.RecyclerView>

    </ScrollView>

    <EditText
        android:id="@+id/edit"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        app:layout_constraintBottom_toTopOf="@+id/botton_text"
        android:text="爱上;的六块腹肌啊;了啊;" />

    <TextView
        android:id="@+id/botton_text"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/purple_500"
        android:text="阿迪舒服"
        android:textColor="@color/white"
        android:gravity="center"
        android:textSize="16sp"
        android:layout_marginTop="10dp"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

...

AndroidManifest.xml
//使用自适应
      <activity android:name=".MainActivity"
            android:windowSoftInputMode="adjustResize">
      </activity>

Adapter适配器

public class MySimpleAdapter extends RecyclerView.Adapter<MySimpleAdapter.SimpleViewHolder> {
    String[] mData;
    Context mContext;
    public MySimpleAdapter(Context context, String[] data) {
        mContext = context;
        mData = data;
    }

    @NonNull
    @Override
    public SimpleViewHolder onCreateViewHolder( ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.recyclerview_list_item,parent,false);
        return new SimpleViewHolder(view);
    }

    @Override
    public void onBindViewHolder(MySimpleAdapter.SimpleViewHolder holder, int position) {
        holder.mTextView.setText(mData[position]);
    }

    @Override
    public int getItemCount() {
        return mData.length;
    }

    public class SimpleViewHolder extends RecyclerView.ViewHolder{
        private TextView mTextView;
        public SimpleViewHolder( View itemView) {
            super(itemView);
            mTextView = itemView.findViewById(R.id.textview);
        }
    }
}

MainActivity.java

    /**
     * 测试软键盘自适应
     */
    private void softWindowInput(){
        mRecyclerView = findViewById(R.id.recyclerview);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mAdapter = new MySimpleAdapter(this, mData);
        mRecyclerView.setAdapter(mAdapter);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值