Android获取输入法高度——输入法与页面布局无缝切换

2024-08-23 03:58

本文主要是介绍Android获取输入法高度——输入法与页面布局无缝切换,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在QQ或者微信的聊天页面,当输入法和表情栏互相切换时,过度非常自然,而且表情栏高度刚好跟输入法一样。个人感觉这种用户体验特别的好,别看这个细节小,但代码实现处理起来还是有一定难度。今天我就带大家来实现这种效果,下面是效果图:



首先,我们需要知道输入法的高度,使表情栏的高度与之保持一致。但是Android是没有提供现成的接口给开发者监听输入法的状态,因此需要自定义的KeyboardLayout,监听布局的改变,通过变化前后布局高度差计算出输入法的高度。

public class KeyboardLayout extends FrameLayout {private KeyboardLayoutListener mListener;private boolean mIsKeyboardActive = false; // 输入法是否激活private int mKeyboardHeight = 0; // 输入法高度public KeyboardLayout(Context context) {this(context, null, 0);}public KeyboardLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public KeyboardLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);// 监听布局变化getViewTreeObserver().addOnGlobalLayoutListener(new KeyboardOnGlobalChangeListener());}private class KeyboardOnGlobalChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {int mScreenHeight = 0;private int getScreenHeight() {if (mScreenHeight > 0) {return mScreenHeight;}mScreenHeight = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight();return mScreenHeight;}@Overridepublic void onGlobalLayout() {Rect rect = new Rect();// 获取当前页面窗口的显示范围((Activity) getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);int screenHeight = getScreenHeight();int keyboardHeight = screenHeight - rect.bottom; // 输入法的高度boolean isActive = false;if (Math.abs(keyboardHeight) > screenHeight / 5) {isActive = true; // 超过屏幕五分之一则表示弹出了输入法mKeyboardHeight = keyboardHeight;}mIsKeyboardActive = isActive;if (mListener != null) {mListener.onKeyboardStateChanged(isActive, keyboardHeight);}}}public void setKeyboardListener(KeyboardLayoutListener listener) {mListener = listener;}public KeyboardLayoutListener getKeyboardListener() {return mListener;}public boolean isKeyboardActive() {return mIsKeyboardActive;}/*** 获取输入法高度* @return*/public int getKeyboardHeight() {return mKeyboardHeight;}public interface KeyboardLayoutListener {/*** @param isActive       输入法是否激活* @param keyboardHeight 输入法面板高度*/void onKeyboardStateChanged(boolean isActive, int keyboardHeight);}}
使用

KeyboardLayout加入布局文件中即可,无其他使用限制。从代码中可知,当布局变化时并不需要知道KeyboardLayout的高度来计算输入法高度,KeyboardLayout只是充当一个布局监听器的作用。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent">
...<cn.forward.androids.views.KeyboardLayoutandroid:id="@+id/keyboard_layout"android:layout_width="wrap_content"android:layout_height="wrap_content"/>
...
</FrameLayout>
mKeyboardLayout = (KeyboardLayout) findViewById(R.id.keyboard_layout);
mKeyboardLayout.setKeyboardListener(new KeyboardLayout.KeyboardLayoutListener() {@Overridepublic void onKeyboardStateChanged(boolean isActive, int keyboardHeight) {if (isActive) { // 输入法打开//do something}else {}}});

输入法与页面布局无缝切换

输入法和表情栏切换时,如果只是简单的在切换到输入法时隐藏表情栏,或者切换到表情栏时隐藏输入法,这样过度过程造成布局闪烁一下,如下所示:

这样的效果简直会逼死像我这样有强迫症的人,因此我们需要解决它!造成这种问题的原因是,在显示表情栏时,输入法还没消失,因此表情栏会出现在输入法上面,当输入法消失时,表情栏的位置又被重新调整到底部,因此会造成布局闪烁,同理可以解释切换到输入法时造成闪烁的原因。解决问题的关键主要靠如下两句代码:

// 设置输入法弹起时自动调整布局,使之在输入法之上
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
// 设置输入法弹起时不调整当前布局
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);

当从输入法切换到表情栏时,设置布局为不会重新调整SOFT_INPUT_ADJUST_NOTHING,同时隐藏输入法,显示表情栏,这样当再次切换输入法时,刚好输入法可以挡住表情栏,再把布局设为可自动调整SOFT_INPUT_ADJUST_RESIZE,代码如下:

public class KeyboardLayoutDemo extends Activity {private KeyboardLayout mKeyboardLayout;private View mEmojiView;private Button mEmojiBtn;private EditText mInput;int mKeyboardHeight = 400; // 输入法默认高度为400@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_keyboard_layout);// 起初的布局可自动调整大小getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);mKeyboardLayout = (KeyboardLayout) findViewById(R.id.keyboard_layout);mEmojiView = findViewById(R.id.emoji);mEmojiBtn = (Button) findViewById(R.id.emoji_btn);mInput = (EditText) findViewById(R.id.input);// 点击输入框mInput.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mKeyboardLayout.postDelayed(new Runnable() {@Overridepublic void run() { // 输入法弹出之后,重新调整mEmojiBtn.setSelected(false);mEmojiView.setVisibility(View.GONE);getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);}}, 250); // 延迟一段时间,等待输入法完全弹出}});mEmojiBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mEmojiBtn.setSelected(!mEmojiBtn.isSelected());if (mKeyboardLayout.isKeyboardActive()) { // 输入法打开状态下if (mEmojiBtn.isSelected()) { // 打开表情getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); //  不改变布局,隐藏键盘,emojiView弹出InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);imm.hideSoftInputFromWindow(mInput.getApplicationWindowToken(), 0);mEmojiView.setVisibility(View.VISIBLE);} else {mEmojiView.setVisibility(View.GONE);InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);imm.hideSoftInputFromWindow(mInput.getApplicationWindowToken(), 0);getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);}} else { //  输入法关闭状态下if (mEmojiBtn.isSelected()) {// 设置为不会调整大小,以便输入弹起时布局不会改变。若不设置此属性,输入法弹起时布局会闪一下getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);mEmojiView.setVisibility(View.VISIBLE);} else {getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);mEmojiView.setVisibility(View.GONE);}}}});mKeyboardLayout.setKeyboardListener(new KeyboardLayout.KeyboardLayoutListener() {@Overridepublic void onKeyboardStateChanged(boolean isActive, int keyboardHeight) {if (isActive) { // 输入法打开if (mKeyboardHeight != keyboardHeight) { // 键盘发生改变时才设置emojiView的高度,因为会触发onGlobalLayoutChanged,导致onKeyboardStateChanged再次被调用mKeyboardHeight = keyboardHeight;initEmojiView(); // 每次输入法弹起时,设置emojiView的高度为键盘的高度,以便下次emojiView弹出时刚好等于键盘高度}if (mEmojiBtn.isSelected()) { // 表情打开状态下mEmojiView.setVisibility(View.GONE);mEmojiBtn.setSelected(false);}}}});}// 设置表情栏的高度private void initEmojiView() {ViewGroup.LayoutParams layoutParams = mEmojiView.getLayoutParams();layoutParams.height = mKeyboardHeight;mEmojiView.setLayoutParams(layoutParams);}
}

实践中会不断的改进的代码,请大家关注最新完整的代码: https://github.com/1993hzw/Androids

这篇关于Android获取输入法高度——输入法与页面布局无缝切换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1098288

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

韦季李输入法_输入法和鼠标的深度融合

在数字化输入的新纪元,传统键盘输入方式正悄然进化。以往,面对实体键盘,我们常需目光游离于屏幕与键盘之间,以确认指尖下的精准位置。而屏幕键盘虽直观可见,却常因占据屏幕空间,迫使我们在操作与视野间做出妥协,频繁调整布局以兼顾输入与界面浏览。 幸而,韦季李输入法的横空出世,彻底颠覆了这一现状。它不仅对输入界面进行了革命性的重构,更巧妙地将鼠标这一传统外设融入其中,开创了一种前所未有的交互体验。 想象

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使