Android: 实现类似QQ、微信的表情输入键盘
来源:互联网 发布:node.js安装 编辑:程序博客网 时间:2024/04/29 00:27
需求
最近在写北邮人论坛客户端时,有一个需求是实现像手机QQ、微信那样的表情输入键盘,效果图:
表情键盘本身并不难做,无非就是一个带SlidingTab的ViewPager,困扰我的地方在于,如何正确处理系统软键盘与表情键盘之间的显隐关系。
Google了一下,大概有这么几种思路:
第一种:动态改变SoftInputMode
这篇博文是国内网上转载比较多的方法,软键盘显示时将SoftInputMode设置为「stateVisible|adjustResize」,表情键盘显示时调整为「adjustPan」。
但在我实际使用过程中效果并不理想,一是我需要在一个ListView的底部实现表情键盘,这样动态更改SoftInputMode会导致ListView上下跳动;二是切换到别的界面再切换回来时软键盘的显隐状态偶尔会有冲突,最终我放弃了这种方法。
第二种:Dialog
Emoticons-Keyboard,这个项目的实现方法是直接在软键盘上覆盖显示一个Dialog,避开了大部分的显示逻辑操作,思路非常独特,可惜我编译运行后发现显示效果并不好,除了动画效果,最大的问题仍然是是从别的界面切换过来时,与软键盘的显示有冲突
基本思路
上面提到的两个项目给了我很大的启发,我反复尝试了微信、微博、手机QQ等应用的表情键盘逻辑,发现它们切换键盘并不会导致ListView跳动,如果没有别的什么黑科技的话,基本可以断定使用的SoftInputMode就是adjustPan。(SoftInputMode各个属性值的意义)
既然是adjustPan就好说了,软键盘显示的时候不会导致ListView跳动,那么Activity的底部必然有一个跟软键盘相同高度的View被软键盘覆盖了,这个View其实就是表情输入键盘,这样点击表情按钮的时候只需要显示隐藏软键盘,背后的表情框就显示出来了。
思路有了,接下来就是梳理一下所需要的技术点:
- 如何检测软键盘高度(用于动态设置表情键盘的高度)?
- 在代码中如何手动显示/隐藏软键盘?
- 如何防止从别的界面切换过来时,软键盘状态改变了有可能导致的显示冲突?
如果这三个问题解决了,需求就基本实现了。
检测软键盘的高度
直接上代码:
private int getSupportSoftInputHeight() { Rect r = new Rect(); mActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r); int screenHeight = mContext.getWindow().getDecorView().getRootView().getHeight(); int softInputHeight = screenHeight - r.bottom; if (Build.VERSION.SDK_INT >= 20) { // When SDK Level >= 20 (Android L), the softInputHeight will contain the height of softButtonsBar (if has) softInputHeight = softInputHeight - getSoftButtonsBarHeight(); } return softInputHeight;}
这里的原理是通过当前的Activity拿到其RootView的高度,减去Activity本身实际的高度,就等于软键盘的高度了。但在实际应用过程中发现,某些Android版本下,没有显示软键盘时减出来的高度总是144,而不是零,经过反复研究,最后发现这个高度是包括了虚拟按键栏的,所以在API Level高于18时,我们需要减去底部虚拟按键栏的高度(如果有的话)。
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)private int getSoftButtonsBarHeight() { DisplayMetrics metrics = new DisplayMetrics(); mContext.getWindowManager().getDefaultDisplay().getMetrics(metrics); int usableHeight = metrics.heightPixels; mContext.getWindowManager().getDefaultDisplay().getRealMetrics(metrics); int realHeight = metrics.heightPixels; if (realHeight > usableHeight) { return realHeight - usableHeight; } else { return 0; }}
将高度设置给表情键盘就比较简单了:
LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) mEmotionLayout.getLayoutParams();linearParams.height = getSupportSoftInputHeight();
在代码中手动显示、隐藏软键盘
也是直接上代码了,这两个方法也比较容易查到:
private void showSoftInput() { mInputManager.showSoftInput(mEditText, 0);}private void hideSoftInput() { mInputManager.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);}
解决切换程序时的显示冲突
在默认状态(StateUnspecified)下,在程序内打开软键盘然后点击Home键或多任务键切换出去时,软键盘会收起。再次进入程序界面也不会打开,前文提到的两个项目就是在这种情况下会出现问题。如何保证软键盘和表情键盘的同步,直观反应就是监听软键盘的高度变化,查了一下,果然可以监听:
mEditText.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int softInputHeight = getSupportSoftInputHeight(); if (softInputHeight != lastSoftInputHeight) { // do Something } }});
实际测试中,这个函数在运行时会调用很多次,我们只需要在高度变化时做处理即可。
如上图,一共有三种状态,表情键盘的状态分别为:gone、invisible和visible。分别判断这三个状态之间的转化关系,然后动态的设置Visiblity即可:
public void onGlobalLayout() { int softInputHeight = getSupportSoftInputHeight(); if (softInputHeight != lastSoftInputHeight) { if (softInputHeight <= 0) { lastSoftInputHeight = softInputHeight; if (!notHideEmojiLayout) { mEmotionLayout.setVisibility(View.GONE); } else { notHideEmojiLayout = false; } } else { lastSoftInputHeight = softInputHeight; LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) mEmotionLayout.getLayoutParams(); linearParams.height = softInputHeight; mEmotionLayout.setVisibility(View.INVISIBLE); if (linearParams.height == softInputHeight) { mEmotionLayout.setVisibility(View.INVISIBLE); } else { linearParams.height = softInputHeight; } sp.edit().putInt(SHARE_PREFERENCE_TAG, softInputHeight).apply(); } }}
一点小Bug
由于Android设备的多样性,软键盘高度不一致,所以需要动态的设置表情键盘的高度,然而程序在第一次软键盘弹出后才能检测到软键盘高度,但这时由于表情键盘高度与软键盘不一致,会导致显示有点异常。所以程序会将检测到的高度保存到SharedPreference中,在Activity加载时读出高度即可。
不过即使是这样,在整个程序第一次进入这个界面时还是会显示异常,暂时的解决办法是在其他软键盘弹出的页面检测一次软键盘高度
如果你有更好的办法,请留言交流~
完整代码
本文的完整的代码在我的Github上:Android-EmotionInputDetector,支持Gradle调用,喜欢的话不妨给个Star~
本文首发http://www.dss886.com,转载请注明
- Android: 实现类似QQ、微信的表情输入键盘
- Android: 实现类似QQ、微信的表情输入键盘
- android 实现类似qq表情
- 实现类似QQ、微信聊天界面,标题栏固定,键盘不遮挡底部输入框
- 类似android手机QQ表情实现
- 模仿QQ、微信表情输入框
- Android: 实现表情输入键盘的另外一种思路
- swift实现ios类似微信输入框跟随键盘弹出的效果
- Swift 实现 iOS 类似微信输入框跟随键盘弹出的效果
- swift实现ios类似微信输入框跟随键盘弹出的效果
- swift实现ios类似微信输入框跟随键盘弹出的效果
- IM即时通讯项目讲解(一)--实现类似qq微信表情面板无缝切换
- 用DELPHI、RxRichEdit控件实现类似QQ的表情输入方法
- richTextBox如何实现输入指定的字符显示一个表情图标?类似QQ那样?
- 类似qq聊天表情实现
- 类似qq聊天表情实现
- android QQ表情的实现
- iOS开源组件__仿写QQ/微信聊天键盘(表情,问题,输入框)纯代码,无依赖
- Build iOS AppRTC iOS AppRTC Deep Dive (Pt. 1)
- android点亮屏幕
- Jenkins+Gradle+pmd对Android工程源码进行静态代码分析
- Android 百度地图开发(一)
- java 项目简单操作 mysql
- Android: 实现类似QQ、微信的表情输入键盘
- jquery ajaxfileupload插件的使用
- C#中的隐藏和重写
- Activity生命周期和启动模式整理
- Tomcat性能优化调整
- ccf测试基础训练
- Jquery获取元素标签名称
- Timus 2046 The First Day at School 非常好的一道模拟题
- android SlidingTabLayout实现ViewPager页卡滑动效果