Android-->如何优雅的切换表情和键盘(原理)

网上有很多开源的项目, 但通常都封装的很复杂, 并不能很友好的自定义, 甚至原理都看不清楚.

没关系, 这篇文章就是讲原理的. 让你分分钟都能自定义一个出来.


正常情况下, 当我们切换表情和键盘的时候, Layout会跳动, 体验极其差.

有几个前提需要满足:

<activity
	android:windowSoftInputMode="adjustResize" //这个是必须的
	android:screenOrientation="portrait"  //尽量固定为竖屏, 否则考虑的情况就多了.
/>

布局大概是这样的:

<SoftInputLayout>//这个是自定义的包裹层, 核心布局
	<LinearLayout
		android:layout_weight="1" > //注意这条属性, 关键哦
		//这里用来放内容
	</LinearLayout>
		
	<LinearLayout>
		//这里用来放表情,默认情况下,表情布局是隐藏的;
	</LinearLayout>
</SoftInputLayout>

分析
在不显示表情布局的情况下, 单纯的显示键盘,隐藏键盘. 一切都没有问题;很正常;

但是, 如果你要显示表情的时候, 问题就蹦出来了;#$%^&*各种问题; 我就不描述了;写过的你,应该懂;

解决的办法就是:
当你点击按钮,显示表情:此时需要把内容布局的高度固定(这个高度值, 就是需要计算的关键之一), 其次再显示表情布局.,没了…

其实就是一个高度的问题, 解决了这个高度, 文章也就结束了.

高度的获取

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh){
	//首先需要在此,记录布局的最大高度
	//然后当键盘弹出的时候, 布局高度会变小
	//就可以计算出键盘的高度
	//此时你已经知道了3个高度值: 最大的布局高度值, 当前键盘弹出后布局的高度值, 以及计算出来的键盘高度
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    //拿到第一次的高度, 一般这个时候都是布局的真是高度.之后resize会改变这个高度
    if (oldh == 0) {
        mRawLayoutHeight = h;
    }
    if (mRawLayoutHeight == h) {
        isSoftInputShow = false;
    } else {
        //键盘弹出的时候,高度会变化, 需要隐藏表情布局
        if (mCurrentContentHeight != h) {
            fixContentLayoutHeight(mCurrentContentHeight, h);
        }
        mCurrentContentHeight = h;
        isSoftInputShow = true;
        hideEmojiLayout();
    }
    if (mOnSoftInputChangeListener != null) {
        mOnSoftInputChangeListener.onSoftInputChange(isSoftInputShow, mRawLayoutHeight, h);
    }
}

有了值之后,显示表情就简单了:

显示表情布局

/**
 * 强制内容和表情布局的高度,这样在键盘弹出的时候,就不会导致布局跳动了
 */
public void showEmojiLayout() {
    hideSoftInput(getContext(), this);//不管键盘有没有显示, 先隐藏再说
    int keyboardHeight;
    if (mCurrentContentHeight == 0) {//首次进入布局的时候,如果键盘之前没有显示过,则使用默认的高度
        keyboardHeight = getDefaultEmojiHeight();
        mCurrentContentHeight = mRawLayoutHeight - keyboardHeight;
    } else {
        keyboardHeight = mRawLayoutHeight - mCurrentContentHeight;
    }
	//主要是计算 键盘的高度和内容的高度, 用来固定布局, 这样resize 就不会跳动了;
    LayoutParams contentParams = (LayoutParams) mContentLayout.getLayoutParams();
    contentParams.height = mCurrentContentHeight;//固定内容布局的高度
    contentParams.weight = 0;
    LayoutParams emojiParams = (LayoutParams) mEmojiLayout.getLayoutParams();
    emojiParams.height = keyboardHeight;//固定表情布局的高度
    emojiParams.weight = 0;
    mEmojiLayout.setVisibility(VISIBLE);
    requestLayout();//刷新一下
    isEmojiLayoutShow = true;
}

隐藏表情布局

/**
 * 恢复成默认就行了, 这里就简单了许多;
 */
public void hideEmojiLayout() {
    LayoutParams params = (LayoutParams) mContentLayout.getLayoutParams();
    params.height = 0;
    params.weight = 1;//注意此处, 这里千万不能固定高度; 否则键盘弹出的时候,就看不到输入框了...
    LayoutParams params2 = (LayoutParams) mEmojiLayout.getLayoutParams();
    params2.height = 0;
    params2.weight = 0;
    mEmojiLayout.setVisibility(GONE);
    isEmojiLayoutShow = false;
    requestLayout();
}

/**
 * 修改第一次打开表情之前, 键盘没有弹出之前的BUG.
 */
private void fixContentLayoutHeight(final int oldH, final int newH) {
    postDelayed(new Runnable() {
        @Override
        public void run() {
            LayoutParams params = (LayoutParams) mContentLayout.getLayoutParams();
            params.height = newH;
            params.weight = 0;
            requestLayout();
            unlockContentLayoutHeight();
        }
    }, 100);
}

/**
 * 此方法的作用就是在键盘弹出后,然后按下了键盘上的关闭键盘按钮, 布局能自适应.
 */
private void unlockContentLayoutHeight() {
    postDelayed(new Runnable() {
        @Override
        public void run() {
            LayoutParams params = (LayoutParams) mContentLayout.getLayoutParams();
            params.height = 0;
            params.weight = 1;
            requestLayout();
        }
    }, 300);
}

项目源码:
https://github.com/Redbird/KeyboardDemo

核心文件:
https://github.com/Redbird/KeyboardDemo/blob/master/app/src/main/java/com/angcyo/keyboarddemo/SoftInputLayout.java

使用方法:

//当需要显示表情的时候调用:
showEmojiLayout()
//当需要隐藏表情的时候调用:
hideEmojiLayout()
//即可

更新

针对部分问题, 调整了实现方式请参考:

Android–›键盘表情切换的终极解决方案(已重构)


至此: 文章就结束了,如有疑问: QQ群:274306954 欢迎您的加入.

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值