最近项目需要实现一个类似微信输入面板的功能,界面很好实现,实现后发现都很好,但有一个非常不好的体验,就是面板和输入法切换时闪烁很严重,于是赶紧百度一下,发现很多这方面的帖子,看了之后有一些收获但还是没有解决,后来又尝试了一个开源项目,但使用起来颇复杂,而且sdk版本和我们项目也不一致,引入有些麻烦,于是还是思考自己解决,后来使用动态设置windowSoftInputMode方法实现了,最终效果和微信一模一样。
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/linear_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:focusable="true"
android:focusableInTouchMode="true"
android:background="?color_interesting_detail_background">
<!-- 输入面板顶部线条 -->
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="?color_comment_title_underline"/>
<!-- 工具栏条(语音按钮,编辑框,表情按钮,扩展按钮) -->
<RelativeLayout
android:id="@+id/relative_input_bar"
android:layout_marginTop="9dp"
android:layout_marginBottom="9dp"
android:clipChildren="false"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/image_voice"
android:layout_marginLeft="10dp"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentLeft="true"
android:src="@drawable/selector_chat_voice_button"/>
<LinearLayout
android:id="@+id/linear_right_area"
android:layout_marginRight="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_alignParentRight="true">
<ImageView
android:id="@+id/image_emoji"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/selector_chat_emoji_button"/>
<ImageView
android:id="@+id/image_ext_button"
android:layout_marginLeft="15dp"
android:layout_width="32dp"
android:layout_height="32dp"
android:visibility="visible"
android:src="@drawable/selector_chat_ext_button"/>
<TextView
android:id="@+id/text_send_button"
android:layout_marginLeft="6dp"
android:layout_width="41dp"
android:layout_height="30dp"
android:visibility="gone"
android:clickable="true"
android:background="?drawable_send_button_background"
android:gravity="center"
android:textColor="?color_button_text"
android:textSize="14sp"
android:text="@string/caption_send_message"/>
</LinearLayout>
<LinearLayout
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/image_voice"
android:layout_toLeftOf="@id/linear_right_area" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/edit_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="32dp"
android:maxHeight="97dp"
android:gravity="center_vertical"
android:textSize="16sp"
android:textColor="?color_activity_text"
android:hint="@string/hint_edit_input"
android:textColorHint="?color_hint_text"
android:background="@null" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="?color_edit_border_gray_dark" />
</LinearLayout>
</RelativeLayout>
<!-- 面板内容区 -->
<RelativeLayout
android:id="@+id/relative_ext_area"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
<!-- 顶部线条 -->
<View
android:id="@+id/view_top_line"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="?color_edit_border_gray_dark" />
<!-- 语音输入面板 -->
<LinearLayout
android:id="@+id/linear_voice_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone"
android:layout_below="@id/view_top_line">
<TextView
android:layout_margin="30dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Voice"/>
</LinearLayout>
<!-- 表情输入面板 -->
<LinearLayout
android:id="@+id/linear_emoji_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone"
android:layout_below="@id/view_top_line">
<TextView
android:layout_margin="30dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Emoji"/>
</LinearLayout>
<!-- 扩展输入面板 -->
<LinearLayout
android:id="@+id/linear_ext_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone"
android:layout_below="@id/view_top_line">
<LinearLayout
android:layout_marginTop="30dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<!-- 图片按钮 -->
<LinearLayout
android:id="@+id/linear_ext_image_button"
android:layout_marginLeft="27dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="56dp"
android:layout_height="56dp"
android:orientation="vertical"
android:background="?drawable_chat_ext_button_background"
android:clickable="true"
android:gravity="center">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:contentDescription="@string/img_desc"
android:src="?drawable_chat_image_icon"/>
</LinearLayout>
<TextView
android:layout_marginTop="4dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="?color_nickname_and_time_text"
android:text="@string/caption_image"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
代码文件
/**
* 初始化页面元素
*/
private void initViews()
{
KeyboardViewUtils.bindLayout(findViewById(R.id.relative_container)); //此处是为了获取键盘高度
mInputArea = findViewById(R.id.message_input);
mInputBar = (RelativeLayout)findViewById(R.id.relative_input_bar);
mVoiceBtn = (ImageView)findViewById(R.id.image_voice);
mRightBtns = (LinearLayout)findViewById(R.id.linear_right_area);
mVoiceBtn = (ImageView)findViewById(R.id.image_voice);
mVoiceBtn.setOnClickListener(this);
mEmojiBtn = (ImageView)findViewById(R.id.image_emoji);
mEmojiBtn.setOnClickListener(this);
mExtBtn = (ImageView)findViewById(R.id.image_ext_button);
mExtBtn.setOnClickListener(this);
mSendBtn = (TextView)findViewById(R.id.text_send_button);
mSendBtn.setOnClickListener(this);
mEdit = (EditText)findViewById(R.id.edit_content);
mEdit.setOnFocusChangeListener(onEditFocusChangeListener);
mEdit.setOnClickListener(onEditClickListener);
mEdit.addTextChangedListener(onEditTextChangeListener);
mEdit.addOnLayoutChangeListener(onEditLayoutChangeListener);
mExtArea = (RelativeLayout)findViewById(R.id.relative_ext_area);
mVoiceView = (LinearLayout)findViewById(R.id.linear_voice_view);
mEmojiView = (LinearLayout)findViewById(R.id.linear_emoji_view);
mExtView = (LinearLayout)findViewById(R.id.linear_ext_view);
}
/**
* 显示面板
* @param type 0:语音 1:表情 2:扩展
*/
private void showExtView(int type)
{
if (mExtArea.getVisibility() != View.VISIBLE) {
mEdit.clearFocus();
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
//关闭键盘
Activity a = ActivityStack.getForgroundActivity();
if (a != null && !a.isFinishing()) {
DisplayUtils.closeInputboard(a);
}
ViewGroup.LayoutParams lp = mExtArea.getLayoutParams();
lp.height = KeyboardViewUtils.getKeyboardHeight();
mExtArea.setLayoutParams(lp);
mExtArea.setVisibility(View.VISIBLE);
if (!DisplayUtils.inputboardIsShowned(this)) { //判断键盘是否显示
//弹出动画
Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide_in_from_bottom);
anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mInputArea.setAnimation(anim);
anim.start();
}
}
if (type == 0)
{
mEmojiView.setVisibility(View.GONE);
mExtView.setVisibility(View.GONE);
mVoiceView.setVisibility(View.VISIBLE);
}
else if (type == 1)
{
mExtView.setVisibility(View.GONE);
mVoiceView.setVisibility(View.GONE);
mEmojiView.setVisibility(View.VISIBLE);
}
else if (type == 2)
{
mEmojiView.setVisibility(View.GONE);
mVoiceView.setVisibility(View.GONE);
mExtView.setVisibility(View.VISIBLE);
}
}
/*
* 显示输入法
*/
private void showInputKeyboard()
{
mEdit.requestFocus();
//打开输入法
Activity a = ActivityStack.getForgroundActivity();
if (a != null && !a.isFinishing()) {
DisplayUtils.openInputboard(a);
}
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mExtArea.setVisibility(View.GONE);
mVoiceView.setVisibility(View.GONE);
mEmojiView.setVisibility(View.GONE);
mExtView.setVisibility(View.GONE);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
}, 300);
}
/*
* 重置输入面板,恢复只显示工具栏状态
*/
private void resetInputBar()
{
mVoiceBtn.setSelected(false);
mEmojiBtn.setSelected(false);
mExtBtn.setSelected(false);
if (DisplayUtils.inputboardIsShowned(this)) {
mExtArea.setVisibility(View.GONE);
mVoiceView.setVisibility(View.GONE);
mEmojiView.setVisibility(View.GONE);
mExtView.setVisibility(View.GONE);
DisplayUtils.closeInputboard(this); //关闭键盘
} else {
//关闭面板动画
Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide_out_from_bottom);
anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mExtArea.setVisibility(View.GONE);
mVoiceView.setVisibility(View.GONE);
mEmojiView.setVisibility(View.GONE);
mExtView.setVisibility(View.GONE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mInputArea.setAnimation(anim);
anim.start();
}
}
KeyboardViewUtils代码
public class KeyboardViewUtils {
private final static int sDefaultHeight = 570;
private static String mSaveName = "keyboard_height";
private static View mRootView;
public static int getKeyboardHeight()
{
Context context = App.getContext();
return SPConfig.getPropertyAsInt(context, mSaveName, sDefaultHeight);
}
public static void bindLayout(View view)
{
if (view != null) {
mRootView = view;
mRootView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
}
}
private static ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener =
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Context context = App.getContext();
Activity a = ActivityStack.getForgroundActivity();
if (a != null && !a.isFinishing()) {
Rect r = new Rect();
mRootView.getGlobalVisibleRect(r);
int viewHeight = r.height();
int statusHeight = DisplayUtils.getStatusbarHeightPx(context); //获得状态栏高度
int titleHeight = DisplayUtils.dp2px(context, 50); //标题栏高度
int screenHeight = DisplayUtils.getScreenHeightPx(context); //屏幕高度
if (viewHeight + statusHeight + titleHeight + 100 < screenHeight) {
int keyboardHeight = screenHeight - viewHeight - statusHeight - titleHeight;
SPConfig.setProperty(context, mSaveName, keyboardHeight);
}
}
}
};
以上代码是此功能的重要部分,其他还有一些业务和EditText的相关处理,如EditText根据输入内容自动撑开等等,没有什么难点这里就不贴代码了。
上面的代码基本上拷贝过去就能用,如果不能,大家可以自己调试一下,这样收获会更大,毕竟直接用别人的代码不如自己理解更重要。
在Oppo R9、华为荣耀X4、HTC 测试通过