Java代码动态设置SoftInputMode,友好进行底部界面呈现
来源:互联网 发布:迷宫寻路算法 编辑:程序博客网 时间:2024/05/16 06:59
前几天在定制短信应用,其中我们经过讨论把短信编辑界面的添加各类附件入口,由原来弹框的形式改为类似微信底部添加附件的方式。涉及到软键盘的呈现以及附件界面的呈现,以及它们之间的切换。如下这几种情况:
这个时候如果我点击输入框,希望软键盘能够把聊天界面往上顶起。
这个时候如果我点击输入框,希望软键盘能够覆盖在附件界面之上
这种时候如果我点击右方的加号按钮,我希望软键盘隐藏,附件直接出现。
如果我按返回按键或者输入法下箭头,整个聊天界面下移到正常。
首先我们先了解软键盘呈现的方式,方式可以在AndroidManifest.xml里面进行配置,
adjustNothing 布局不变,软键盘覆盖当前布局
adjustResize 布局会被软键盘顶起,布局高度缩小
adjustPan 布局高度不变,上移动,腾出足够空间给软键盘,ActionBar上移
adjustUnspecified 系统根据条件选择adjustResize 和 adjustPan
这几种方式也可以在代码里通过调用当前窗口的setSoftInputMode方法进行设置。
了解了以上,我们知道如果想要满足需求,我们有以下几方面需要做到:
1、获取软键盘的高度并且设置附件的高度与它一致
2、在不同的条件下,让软键盘以不同的方式呈现
获取软键盘的高度
有以下两种方式:
1、
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { //获取屏幕的高度 int screenHeight = ((Activity)context).getWindowManager().getDefaultDisplay().getHeight(); Rect rect = new Rect(); getWindowVisibleDisplayFrame(rect); // 获取可见区域 if (screenHeight - rect.bottom > 0.4 * screenHeight) { int softInputHeight = screenHeight - rect.bottom; // 通知对附件的高度进行计算等 } } });
2、
在最外层布局的onSizeChanged回调方法中,告知监听者高度已改变,由监听者去计算软键盘的高度,分两部分,
a、自定义HeightChangedLinearLayout布局,重写onSizeChanged方法
public class HeightChangedLinearLayout extends LinearLayout { @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (DEBUG)Log.d(TAG, "onSizeChanged(): oldw = " + oldw + ", oldh = " + oldh + ",w = " + w + ", h = " + h); final int fw = w; final int fh = h; final int fow = oldw; final int foh = oldh; if (mListener != null) { new Thread(new Runnable() { @Override public void run() { mListener.onLayoutSizeChanged(fw, fh, fow, foh); } }).start(); } }}
b、实现监听者
HeightChangedLinearLayout heightChangedLinearLayout = (HeightChangedLinearLayout)findViewById(R.id.height_change_layout); heightChangedLinearLayout.setListener(new HeightChangedLinearLayout.LayoutSizeChangedListener() { @Override public void onLayoutSizeChanged(int w, int h, int oldw, int oldh) { int softInputHeight = mSoftInputHeight; Log.d(TAG, "h: " + h + ", oldh: " + oldh); if (h - oldh > SOFT_KEY_BOARD_MIN_HEIGHT) { mIsSoftInputShown = false; } else { /* 获取到软键盘的高度*/ softInputHeight = Math.abs(h - oldh); mIsSoftInputShown = true; } Log.d(TAG, "onLayoutSizeChanged, mIsSoftInputShown: " + mIsSoftInputShown); if (softInputHeight != mSoftInputHeight) { if (DEBUG)Log.d(TAG, "New mSoftInputHeight: " + softInputHeight); mSoftInputHeight = softInputHeight; /*更新附件的高度*/ mUiHandler.post(new Runnable() { @Override public void run() { setAttachmentPanelHeight(); } }); } } });
让软键盘以不同的方式呈现
这里就要求应用能够根据当前条件切换软键盘呈现方式了,以及尽量做到不要让软键盘与附件同时存在,否则 【如果我按返回按键或者输入法下箭头,整个聊天界面下移到正常】 该需求难以实现,我在下面贴出我的例子Activity代码,里面有注释的。
package com.jc.softinput;import android.content.Context;import android.os.Handler;import android.os.Looper;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.WindowManager;import android.view.inputmethod.InputMethodManager;import android.widget.EditText;import android.widget.ImageButton;import android.widget.LinearLayout;import android.widget.TextView;public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final boolean DEBUG = true; private static final String TAG = "MainActivity"; /*软键盘最小高度,这个的来源有点有点奇怪*/ private static final int SOFT_KEY_BOARD_MIN_HEIGHT = 150; private static final int DELAY_BEFORE_HIDE_ATTACHMENT = 400; // ms private boolean mIsSoftInputShown = false; /* 软键盘的初始化高度,可以根据不同分辨率分别指定*/ private int mSoftInputHeight = 554; /*假设该界面是类似微信的附件界面,包含拍照、录像等入口*/ private LinearLayout mAttachmentPanel; private Handler mUiHandler; private ImageButton mImageButton; private EditText mTextEditor; /*聊天内容界面通常是以ListView的形式呈现*/ private TextView mContentPanel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContentPanel = (TextView)findViewById(R.id.contentPanel); mContentPanel.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { setSoftInputAdjustResize(); mAttachmentPanel.setVisibility(View.GONE); hideSoftInputMethod(); return true; } }); mUiHandler = new Handler(Looper.getMainLooper()); /*初始化附件的高度,这里通常设置为272dp*/ mSoftInputHeight = getResources().getDimensionPixelSize(R.dimen.init_soft_input_height); mAttachmentPanel = (LinearLayout)findViewById(R.id.attachment_panel); setAttachmentPanelHeight(); mImageButton = (ImageButton)findViewById(R.id.img); mImageButton.setOnClickListener(this); mTextEditor = (EditText)findViewById(R.id.editText); mTextEditor.setFocusable(true); mTextEditor.setFocusableInTouchMode(true); mTextEditor.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View view, boolean hasFocus) { if (DEBUG) Log.d(TAG, "mTextEditor hasFocus: " + hasFocus); /* 输入框获取到焦点之后,弹起了软键盘,这个时候如果附件是可见的,说明软键盘是以覆盖的形式出现的,我们延迟 0.4 s之后, 先把软键盘呈现的方式设置成往上顶,然后偷偷的把附件隐藏,神不知鬼不觉,非常友好的让软键盘接替了附件。 */ if (hasFocus) { if (View.VISIBLE == mAttachmentPanel.getVisibility()) { mUiHandler.postDelayed(new Runnable() { @Override public void run() { if (DEBUG)Log.d(TAG, "hide attachment panel"); setSoftInputAdjustResize(); mAttachmentPanel.setVisibility(View.GONE); } }, DELAY_BEFORE_HIDE_ATTACHMENT); } } } }); mImageButton.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (DEBUG) Log.d(TAG, "mImageButton hasFocus: " + hasFocus); if (hasFocus) { onClick(mImageButton); } } }); HeightChangedLinearLayout heightChangedLinearLayout = (HeightChangedLinearLayout)findViewById(R.id.height_change_layout); heightChangedLinearLayout.setListener(new HeightChangedLinearLayout.LayoutSizeChangedListener() { @Override public void onLayoutSizeChanged(int w, int h, int oldw, int oldh) { int softInputHeight = mSoftInputHeight; Log.d(TAG, "h: " + h + ", oldh: " + oldh); if (h - oldh > SOFT_KEY_BOARD_MIN_HEIGHT) { mIsSoftInputShown = false; } else { /* 获取到软键盘的高度*/ softInputHeight = Math.abs(h - oldh); mIsSoftInputShown = true; } Log.d(TAG, "onLayoutSizeChanged, mIsSoftInputShown: " + mIsSoftInputShown); if (softInputHeight != mSoftInputHeight) { if (DEBUG)Log.d(TAG, "New mSoftInputHeight: " + softInputHeight); mSoftInputHeight = softInputHeight; /*更新附件的高度*/ mUiHandler.post(new Runnable() { @Override public void run() { setAttachmentPanelHeight(); } }); } } }); } /* 重新计算附件的高度*/ private void setAttachmentPanelHeight() { ViewGroup.LayoutParams layoutParams = mAttachmentPanel.getLayoutParams(); layoutParams.height = mSoftInputHeight; mAttachmentPanel.setLayoutParams(layoutParams); } /* 隐藏收入法 */ private void hideSoftInputMethod() { InputMethodManager im = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); im.hideSoftInputFromWindow(getCurrentFocus().getApplicationWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && mAttachmentPanel.getVisibility() == View.VISIBLE) { setSoftInputAdjustResize(); mAttachmentPanel.setVisibility(View.GONE); return true; } return super.onKeyDown(keyCode, event); } /*软键盘以覆盖当前界面的形式出现*/ private void setSoftInputAdjustNothing(){ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); } /*软键盘以顶起当前界面的形式出现, 注意这种方式会使得当前布局的高度发生变化,触发当前布局onSizeChanged方法回调,这里前后高度差就是软键盘的高度了*/ private void setSoftInputAdjustResize(){ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); } @Override public void onClick(View view) { if (view == mImageButton) { Log.d(TAG, "mIsSoftInputShown: " + mIsSoftInputShown + ", visible: " + mAttachmentPanel.getVisibility()); if (mIsSoftInputShown) { /*软键盘存在,但附件不存在的时候,显示附件,隐藏软键盘,设置下一次出现方式为覆盖 */ if (mAttachmentPanel.getVisibility() == View.GONE) { mAttachmentPanel.setVisibility(View.VISIBLE); hideSoftInputMethod(); mTextEditor.clearFocus(); setSoftInputAdjustNothing(); } else { /* 在用户点击弹附件按钮的时候,附件和软键盘同时存在的可能性很小,只隐藏软键盘吧 */ setSoftInputAdjustResize(); hideSoftInputMethod(); } } else { /* 软键盘不存在 */ if (mAttachmentPanel.getVisibility() == View.GONE) { mTextEditor.clearFocus(); setSoftInputAdjustNothing(); mAttachmentPanel.setVisibility(View.VISIBLE); } else { mAttachmentPanel.setVisibility(View.GONE); setSoftInputAdjustResize(); } } } }}
以上是部分代码实现,关键点已经添加注释。
注意点: 在做短信信息编辑界面的时候,发现新建一条没有收件人的新短信时候,通过代码设置SoftInputMode能友好切换。但是从已有收件人进入到编辑界面后发现设置adjustNothing,软键盘还是把布局给顶上去。纠结了很久(一个Activity 一万 多行,实在不知道怎么找出原因),最才发现新建的信息实在初始化的时候设置了 adjustReszie 先, 最后在有收件人的情况下也先设置adjustResize先,莫名其妙就正常了。
所以记得在AndroidManifest.xml 或者 Activity 初始化的时候 设置 adjustResize.
完整代码请查看这里: https://git.oschina.net/jcxxxxx/SoftInput
欢迎交流。
- Java代码动态设置SoftInputMode,友好进行底部界面呈现
- Web应用设置统一错误友好界面
- Android 通过Java代码生成创建界面。动态生成View,动态设置View属性。addRules详解
- Android 通过Java代码生成创建界面。动态生成View,动态设置View属性。addRules详解
- Android softkeyboard 和 其他界面关系 softInputMode
- java代码动态设置属性
- 仿推特进入设置界面友好的指示提示框
- Java界面背景图片设置的关键代码
- 纯java代码设置简单UI界面
- 友好界面menu
- 用户友好输入界面
- 用户友好界面
- java代码动态设置控件的颜色
- 代码设置界面
- 你的Java代码对JIT编译友好么?
- 你的Java代码对JIT编译友好么?
- 友好代码注释
- 友好型的ui界面
- 关于php安全
- Redis和nosql简介,api调用;Redis数据功能(String类型的数据处理);List数据结构(及Java调用处理);Hash数据结构;Set数据结构功能;sortedSet(有序集合)数
- js判断移动端与pc端
- 普通Queue与PriorityQueue的区别
- HHU2017(一)数论
- Java代码动态设置SoftInputMode,友好进行底部界面呈现
- Rails文件结构
- [Leetcode] 59. Spiral Matrix II 解题报告
- angular 函数表达式执行两次的问题
- Shader自学笔记1.2 结构体作为函数的参数和返回值
- SpringData JPA查询分页demo
- 2017计划
- Android中AsyncTask分析--你所不注意的坑
- 微信小程序填坑篇(一)