Android 表情面板和软键盘切换时跳闪问题的解决方法

现在很多应用都会在让用户输入各种文本信息的时候同时多提供一个表情面板,这样就会出现一个问题,即表情面板的跳闪问题要输入文本信息,那固然是需要弹出软键盘,在软键盘显示的情况下,此时如果要切换显示出表情面板,由于表情面板不可能和用户的软键盘高度恰好一样,此外由于控件的上下移位,就会出现表情面板的跳闪现象

在点击切换按钮的时候,表情面板会先向上跳,然后再往下移,这样就会带来很差的用户体验,效果如下图所示:

这里提供一个解决方案,使软键盘和表情面板可以很自然地切换,效果如下图所示:

解决思路主要是这样:系统在弹出软键盘时,会将内容输入框View以及其之上的View都给顶上去,当切换到表情面板时,只有将表情面板的高度保持为和软键盘的高度一致,才能自然地切换。此外,还需要将内容输入框View以及其之上的View的位置固定住,这样才不会出现跳闪问题

主要的操作逻辑都在 EmojiKeyboard 类中

/**
 * 作者: chenZY
 * 时间: 2017/8/26 18:12
 * 描述:
 */
public class EmojiKeyboard {
 private Activity activity;
 //文本输入框
 private EditText editText;
 //表情面板
 private View emojiPanelView;
 //内容View,即除了表情布局和输入框布局以外的布局
 //用于固定输入框一行的高度以防止跳闪
 private View contentView;
 private InputMethodManager inputMethodManager;
 private SharedPreferences sharedPreferences;
 private static final String EMOJI_KEYBOARD = "EmojiKeyboard";
 private static final String KEY_SOFT_KEYBOARD_HEIGHT = "SoftKeyboardHeight";
 private static final int SOFT_KEYBOARD_HEIGHT_DEFAULT = 654;
 private Handler handler;
 public EmojiKeyboard(Activity activity, EditText editText, View emojiPanelView, View emojiPanelSwitchView, View contentView) {
  init(activity, editText, emojiPanelView, emojiPanelSwitchView, contentView);
 }
 private void init(Activity activity, EditText editText, View emojiPanelView, View emojiPanelSwitchView, View contentView) {
  this.activity = activity;
  this.editText = editText;
  this.emojiPanelView = emojiPanelView;
  this.contentView = contentView;
  this.editText.setOnTouchListener(new View.OnTouchListener() {
   @Override
   public boolean onTouch(final View v, MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_UP && EmojiKeyboard.this.emojiPanelView.isShown()) {
     lockContentViewHeight();
     hideEmojiPanel(true);
     unlockContentViewHeight();
    }
    return false;
   }
  });
  this.contentView.setOnTouchListener(new View.OnTouchListener() {
   @Override
   public boolean onTouch(View view, MotionEvent motionEvent) {
    if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
     if (EmojiKeyboard.this.emojiPanelView.isShown()) {
      hideEmojiPanel(false);
     } else if (isSoftKeyboardShown()) {
      hideSoftKeyboard();
     }
    }
    return false;
   }
  });
  //用于弹出表情面板的View
  emojiPanelSwitchView.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    if (EmojiKeyboard.this.emojiPanelView.isShown()) {
     lockContentViewHeight();
     hideEmojiPanel(true);
     unlockContentViewHeight();
    } else {
     if (isSoftKeyboardShown()) {
      lockContentViewHeight();
      showEmojiPanel();
      unlockContentViewHeight();
     } else {
      showEmojiPanel();
     }
    }
   }
  });
  this.inputMethodManager = (InputMethodManager) this.activity.getSystemService(Context.INPUT_METHOD_SERVICE);
  this.sharedPreferences = this.activity.getSharedPreferences(EMOJI_KEYBOARD, Context.MODE_PRIVATE);
  this.activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
  this.handler = new Handler();
  init();
 }
 /**
  * 如果之前没有保存过键盘高度值
  * 则在进入Activity时自动打开键盘,并把高度值保存下来
  */
 private void init() {
  if (!sharedPreferences.contains(KEY_SOFT_KEYBOARD_HEIGHT)) {
   handler.postDelayed(new Runnable() {
    @Override
    public void run() {
     showSoftKeyboard(true);
    }
   }, 200);
  }
 }
 /**
  * 当点击返回键时需要先隐藏表情面板
  */
 public boolean interceptBackPress() {
  if (emojiPanelView.isShown()) {
   hideEmojiPanel(false);
   return true;
  }
  return false;
 }
 /**
  * 锁定内容View以防止跳闪
  */
 private void lockContentViewHeight() {
  LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) contentView.getLayoutParams();
  layoutParams.height = contentView.getHeight();
  layoutParams.weight = 0;
 }
 /**
  * 释放锁定的内容View
  */
 private void unlockContentViewHeight() {
  handler.postDelayed(new Runnable() {
   @Override
   public void run() {
    ((LinearLayout.LayoutParams) contentView.getLayoutParams()).weight = 1;
   }
  }, 200);
 }
 /**
  * 获取键盘的高度
  */
 private int getSoftKeyboardHeight() {
  Rect rect = new Rect();
  activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
  //屏幕当前可见高度,不包括状态栏
  int displayHeight = rect.bottom - rect.top;
  //屏幕可用高度
  int availableHeight = ScreenUtils.getAvailableScreenHeight(activity);
  //用于计算键盘高度
  int softInputHeight = availableHeight - displayHeight - ScreenUtils.getStatusBarHeight(activity);
  Log.e("TAG-di", displayHeight + "");
  Log.e("TAG-av", availableHeight + "");
  Log.e("TAG-so", softInputHeight + "");
  if (softInputHeight != 0) {
   // 因为考虑到用户可能会主动调整键盘高度,所以只能是每次获取到键盘高度时都将其存储起来
   sharedPreferences.edit().putInt(KEY_SOFT_KEYBOARD_HEIGHT, softInputHeight).apply();
  }
  return softInputHeight;
 }
 /**
  * 获取本地存储的键盘高度值或者是返回默认值
  */
 private int getSoftKeyboardHeightLocalValue() {
  return sharedPreferences.getInt(KEY_SOFT_KEYBOARD_HEIGHT, SOFT_KEYBOARD_HEIGHT_DEFAULT);
 }
 /**
  * 判断是否显示了键盘
  */
 private boolean isSoftKeyboardShown() {
  return getSoftKeyboardHeight() != 0;
 }
 /**
  * 令编辑框获取焦点并显示键盘
  */
 private void showSoftKeyboard(boolean saveSoftKeyboardHeight) {
  editText.requestFocus();
  inputMethodManager.showSoftInput(editText, 0);
  if (saveSoftKeyboardHeight) {
   handler.postDelayed(new Runnable() {
    @Override
    public void run() {
     getSoftKeyboardHeight();
    }
   }, 200);
  }
 }
 /**
  * 隐藏键盘
  */
 private void hideSoftKeyboard() {
  inputMethodManager.hideSoftInputFromWindow(editText.getWindowToken(), 0);
 }
 /**
  * 显示表情面板
  */
 private void showEmojiPanel() {
  int softKeyboardHeight = getSoftKeyboardHeight();
  if (softKeyboardHeight == 0) {
   softKeyboardHeight = getSoftKeyboardHeightLocalValue();
  } else {
   hideSoftKeyboard();
  }
  emojiPanelView.getLayoutParams().height = softKeyboardHeight;
  emojiPanelView.setVisibility(View.VISIBLE);
  if (emojiPanelVisibilityChangeListener != null) {
   emojiPanelVisibilityChangeListener.onShowEmojiPanel();
  }
 }
 /**
  * 隐藏表情面板,同时指定是否随后开启键盘
  */
 private void hideEmojiPanel(boolean showSoftKeyboard) {
  if (emojiPanelView.isShown()) {
   emojiPanelView.setVisibility(View.GONE);
   if (showSoftKeyboard) {
    showSoftKeyboard(false);
   }
   if (emojiPanelVisibilityChangeListener != null) {
    emojiPanelVisibilityChangeListener.onHideEmojiPanel();
   }
  }
 }
 public interface OnEmojiPanelVisibilityChangeListener {
  void onShowEmojiPanel();
  void onHideEmojiPanel();
 }
 private OnEmojiPanelVisibilityChangeListener emojiPanelVisibilityChangeListener;
 public void setEmoticonPanelVisibilityChangeListener(OnEmojiPanelVisibilityChangeListener emojiPanelVisibilityChangeListener) {
  this.emojiPanelVisibilityChangeListener = emojiPanelVisibilityChangeListener;
 }
}

这里也提供代码下载:Android 解决表情面板和软键盘切换时跳闪的问题

总结

以上所述是小编给大家介绍的Android 表情面板和软键盘切换时跳闪问题的解决方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

时间: 2017-08-26

Android 点击屏幕空白处收起输入法软键盘(手动打开)

很多时候,我们在使用应用时,会出现输入法软键盘弹出的问题,通常情况下,我们默认会使用户点击返回键或者下一步对软键盘进行隐藏.为了更好的体验,我们可以实现当用户使用完毕软键盘时.点击屏幕空白区域即可实现收起输入法软键盘功能.下面给大家介绍下实现方法. 1.//隐藏软键盘   在Java文件: InputMethodManager m = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); m .

Android软键盘弹出时的界面控制方法

本文实例讲述了Android软键盘弹出时的界面控制方法.分享给大家供大家参考,具体如下: 有时候androidactivity弹出软键盘后布局改变 下面有三种模式可以改变软键盘弹出以后的显示形式 模式一:压缩模式软键盘弹出以后,会压缩原先的大小 我们可以在AndroidManifet.xml中对Activity进行设置.如: android:windowSoftInputMode="stateUnchanged|adjustResize" 模式二:平移模式 软键盘弹出以后,不会压缩原先

Android判断软键盘的状态和隐藏软键盘的简单实例

之前本人也遇到一个关于获取软键盘的状态的问题,在网上找了很多资料,基本上回答都是用getWindow().getAttributes().softInputMode==WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED来判断软键盘是否打开,若相等则为打开,然后你就可以根据这段代码进行后续操作了.但是我试了好久,不管是软键盘弹出还是关闭getWindow().getAttributes().softInputMode的值一直是0,至于为什

Android判断软键盘弹出并隐藏的简单完美解决方法(推荐)

最近项目中有一个编辑框,下面是个ListView.在触发编辑框弹出软键盘后,ListView还能滑动,并且ListView的item还能响应单击.这样的体验效果很不好.于是便想在滑动或单击item时判断键盘是否弹出,若弹出,则把它隐藏. 网上一搜,发现Android并没有直接提供软键盘的弹出与隐藏判断,一些解决方案诸如判断父控件的高度或者判断 if(getWindow().getAttributes().softInputMode==WindowManager.LayoutParams.SOFT

Android输入法与表情面板切换时的界面抖动问题解决方法

昨天琢磨了下Android的输入法弹出模式,突然发现利用动态切换输入法的弹出模式可以解决输入法抖动的问题.具体是怎样的抖动呢?我们先看微博的反面教材. [具体表现为:表情面板与输入法面板高度不一致,从而导致弹出输入法(layout被挤压)时,同时又需要隐藏表情面板(layout被拉升),最终让界面产生了高度差抖动,所以在切换时明显会有不大好的抖动体验)] 使用了解决抖动的解决方案后,效果如下: [这样的方案明显比微博的切换更平滑] 老样子,先说思路.主要我们要用到两个输入法弹出模式,分别是:ad

Android 软键盘弹出时把原来布局顶上去的解决方法

键盘弹出时,会将布局底部的导航条顶上去. 解决办法: 在mainfest.xml中,在和导航栏相关的activity中加: <activity android:name=".filing.MainActivity" android:windowSoftInputMode="adjustResize|stateHidden" /> windowSoftInputMode 属性解释: 活动的主窗口如何与包含屏幕上的软键盘窗口交互.这个属性的设置将会影响两件事

Android开发软键盘遮挡登陆按钮的完美解决方案

在应用登陆页面我们需要填写用户名和密码.当填写这些信息的时候,软键盘会遮挡登陆按钮,这使得用户体验较差,所以今天就来解决这个问题 1:登陆布局界面如下 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="

Android软键盘遮挡的四种完美解决方案

一.问题概述 在编辑框输入内容时会弹出软键盘,而手机屏幕区域有限往往会遮住输入界面,我们先看一下问题效果图: 输入用户名和密码时,系统会弹出键盘,造成系统键盘会挡住文本框的问题,如图所示: 输入密码时输入框被系统键盘遮挡了,大大降低了用户操作体验,这就是开发中非常常见的软键盘遮挡的问题,该如何解决? 二.简单解决方案 方法一 在你的activity中的oncreate中setContentView之前写上这个代码 getWindow().setSoftInputMode(WindowManage

Android 6.0调用相机图册崩溃的完美解决方案

最近客户更新系统发现,以前的项目在调用相机的时候,闪退掉了,很奇怪,后来查阅后发现,Android 6.0以后需要程序授权相机权限,默认会给出提示,让用户授权,个人感觉这一特性很好,大概如下: 导入Android V4, V7包! Android Studio 导入很简单,右键项目后找到dependency就ok了. 继承AppCompatActivity public class MainActivity extends AppCompatActivity 引入需要的类库 import and

android虚拟键盘弹出遮挡登陆按钮问题的解决方法

Android虚拟键盘的弹起会遮挡住部分ui,虽然通过在清单文件中设置,可以随着虚拟键盘的弹出,布局往上推,但是面对登陆界面时,并没有太大的作用,这样就会导致用户体验不好:开发中既然出现了就的解决:先说先解决的思路:获取到屏幕的高度.虚拟键盘的高度,布局的高度,用屏幕的高度减去布局的高度,用高度差和虚拟键盘的高度进行对比:代码实现如下: private LinearLayout logo_layout; private ImageView iv_logo; private int sh; pri

Android虚拟导航栏遮挡底部的输入框的解决方法

1.场景还原 最近忙着app的适配,在这个过程问题中,各种机型的奇葩问题都出来了,适配真尼玛痛苦!今天就oppo机型虚拟导航栏遮挡底部的输入框的问题作个记录. 2.解决方法 ① 在该Activity的根layout配置如下属性: android:fitsSystemWindows="true" android:clipToPadding="false" 第一个属性: 如果为true,将调整系统窗口布局以适应你自定义的布局. 第二个属性: 控件的绘制区域是否在padd

Android优雅的方式解决软键盘遮挡按钮问题

前言 比如在进行登录的操作中,用户输入完密码之后,肯定是想直接点击登录按钮的.返回键隐藏软键盘这样的体验肯定很糟糕,程序员,遇到问题解决问题. 实现1 xml <ScrollView android:id="@+id/scrollview" android:layout_width="match_parent" android:layout_height="wrap_content" android:fadingEdge="non

Android 开发之Dialog中隐藏键盘的正确使用方法

Android 开发之Dialog中隐藏键盘的正确使用方法 场景:弹出一个Dialog,里面有一个EditText,用来输入内容,因为输入时,需要弹出键盘,所以当Dialog消失时,键盘要一起隐藏. 现在我们做一个自定义的Dialog MyDialog extends Dialog 一开始认为这个功能很容易实现,于是写了下面的代码 //Dialog的构造函数中写 this.setOnDismissListener(new OnDismissListener() { @Override publi

Android开发之FloatingActionButton悬浮按钮基本使用、字体、颜色用法示例

本文实例讲述了Android开发之FloatingActionButton悬浮按钮基本使用.字体.颜色用法.分享给大家供大家参考,具体如下: 这里主要讲: FloatingActionsMenu自定义样式以及title调整 FloatingActionButton的基本方法 看一下效果图: 这里使用的是:com.getbase.floatingactionbutton.FloatingActionsMenu 先说下它的配置:在app/build.gradle 添加以下代码依赖: 圆形悬浮按钮 i

Android开发之EditText框输入清理工具类示例

本文实例讲述了Android开发之EditText框输入清理工具类.分享给大家供大家参考,具体如下: 这个工具类主要用于清理输入框的.当然有的还要依情况而定 package com.maobang.imsdk.util; import android.text.Editable; import android.text.TextWatcher; import android.view.View; import android.widget.EditText; import android.wid

Android开发之TextView使用intent传递信息,实现注册界面功能示例

本文实例讲述了Android开发之TextView使用intent传递信息,实现注册界面功能.分享给大家供大家参考,具体如下: 使用intent在活动间传递值 首先是 MainActuvity 活动(注册界面 写完个人信息点击注册 ) 跳转到 In 活动 (通过 intent 获得 MainActivity 中的信息 ) 效果图如下: MainActivity 实现: Java代码: public class Home extends AppCompatActivity { //用于存放个人注册