在开发中关于软键盘的需求层出不穷,有些东西以前已经记录过了,最近又遇到一些新的索性一起重新记录一下吧 ~
我的那些软键盘Blog ~
- Android进阶之路 - 常见软键盘操作行为
- Android进阶之路 - 软键盘中右下角的设置与监听
- Android进阶之路 - 软键盘顶起解决方案
- Android进阶之路 - 监听软键盘当前状态,实现布局上移
自动弹出软键盘
/**
* 查看当前键盘状态, 如显示则影藏,如影藏则展示~
*/
private void showKeyboard(){
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.showSoftInput(editText, 0);
}
隐藏软键盘
a方式
/**
*隐藏软键盘
*/
void hintKeyboard() {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputMethodManager.isActive()) {
inputMethodManager.hideSoftInputFromWindow(MainActivity.this.getCurrentFocus().getWindowToken(), 0);
}
}
b方式
/**
* des:隐藏软键盘,这种方式参数为activity
*/
public static void hideInputForce(Activity activity) {
if (activity == null || activity.getCurrentFocus() == null) {
return;
}
InputMethodManager imm = (InputMethodManager) activity.getSystemService(INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
获取软键盘的高度
常规方式
et.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
//当键盘弹出隐藏的时候会 调用此方法。
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//获取当前界面可视部分
MainActivity.this.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
//获取屏幕的高度
int screenHeight = MainActivity.this.getWindow().getDecorView().getRootView().getHeight();
//此处就是用来获取键盘的高度的, 在键盘没有弹出的时候 此高度为0 键盘弹出的时候为一个正数
int heightDifference = screenHeight - r.bottom;
Log.d("Keyboard Size", "Size: " + heightDifference);
}
});
b方式(2022-亲测)
注册监听:一般我们在 Activity 的 onCreate()方法中开始监听
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//......
getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
}
注销监听:当 Activity 被销毁的时候,一定要移除监听,否则就会产生内存泄漏
@Override
protected void onDestroy() {
super.onDestroy();
getWindow().getDecorView().getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener);
}
监听事件
//记录原始窗口高度
private var mWindowHeight = 0
private val mGlobalLayoutListener =
ViewTreeObserver.OnGlobalLayoutListener {
val r = Rect()
//获取当前窗口实际的可见区域
window.decorView.getWindowVisibleDisplayFrame(r)
val height = r.height()
if (mWindowHeight == 0) {
//一般情况下,这是原始的窗口高度
mWindowHeight = height
} else {
if (mWindowHeight != height) {
//两次窗口高度相减,就是软键盘高度
val softKeyboardHeight = mWindowHeight - height
println("SoftKeyboard height = $softKeyboardHeight")
}
}
}
c方式(未亲测)
//一个静态变量存储高度
public static int keyboardHeight = 0;
boolean isVisiableForLast = false;
ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener = null;
public void addOnSoftKeyBoardVisibleListener() {
getKeyboradHeight();
if(keyboardHeight>0){
return;
}
final View decorView = getWindow().getDecorView();
onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();
decorView.getWindowVisibleDisplayFrame(rect);
//计算出可见屏幕的高度
int displayHight = rect.bottom - rect.top;
//获得屏幕整体的高度
int hight = decorView.getHeight();
boolean visible = (double) displayHight / hight < 0.8;
int statusBarHeight = 0;
try {
Class<?> c = Class.forName("com.android.internal.R$dimen");
Object obj = c.newInstance();
Field field = c.getField("status_bar_height");
int x = Integer.parseInt(field.get(obj).toString());
statusBarHeight = getContext().getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
if(visible&&visible!= isVisiableForLast){
//获得键盘高度
keyboardHeight = hight - displayHight-statusBarHeight;
Logger.sl(Log.DEBUG,"MMSL",keyboardHeight);
}
isVisiableForLast = visible;
}
};
decorView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
}
监听软键盘状态(弹出收回)
- 自定义监听类 KeyboardStateObserver(可直接Copy使用)
package 自己的当前的包名
/**
* @author MrLiu
* @date 2019/9/12
* desc
*/
import android.app.Activity;
import android.graphics.Rect;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
public class KeyboardStateObserver {
private static final String TAG = KeyboardStateObserver.class.getSimpleName();
public static KeyboardStateObserver getKeyboardStateObserver(Activity activity) {
return new KeyboardStateObserver(activity);
}
private View mChildOfContent;
private int usableHeightPrevious;
private OnKeyboardVisibilityListener listener;
public void setKeyboardVisibilityListener(OnKeyboardVisibilityListener listener) {
this.listener = listener;
}
private KeyboardStateObserver(Activity activity) {
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
possiblyResizeChildOfContent();
}
});
}
private void possiblyResizeChildOfContent() {
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious) {
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
if (heightDifference > (usableHeightSansKeyboard / 4)) {
if (listener != null) {
listener.onKeyboardShow();
}
} else {
if (listener != null) {
listener.onKeyboardHide();
}
}
usableHeightPrevious = usableHeightNow;
Log.d(TAG,"usableHeightNow: " + usableHeightNow + " | usableHeightSansKeyboard:" + usableHeightSansKeyboard + " | heightDifference:" + heightDifference);
}
}
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
Log.d(TAG,"rec bottom>" + r.bottom + " | rec top>" + r.top);
return (r.bottom - r.top);// 全屏模式下: return r.bottom
}
public interface OnKeyboardVisibilityListener {
void onKeyboardShow();
void onKeyboardHide();
}
}
- 使用方式
注意:此方式必须在弹出键盘时候,使页面原有布局发生变动,所以如果不起作用的话可以试着在AndroidManifest.xml文件中设置android:windowSoftInputMode=”adjustResize|stateHidden“”
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
KeyboardStateObserver.getKeyboardStateObserver(this).
setKeyboardVisibilityListener(new KeyboardStateObserver.OnKeyboardVisibilityListener() {
@Override
public void onKeyboardShow() {
Toast.makeText(MainActivity.this,"键盘弹出",Toast.LENGTH_SHORT).show();
}
@Override
public void onKeyboardHide() {
Toast.makeText(MainActivity.this,"键盘收回",Toast.LENGTH_SHORT).show();
}
});
}
EditText点击外部时候失去焦点
open class BaseActivity: AppCompatActivity() {
var editText: EditText? = null
//使editText点击外部时候失去焦点
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
if (ev.action == MotionEvent.ACTION_DOWN) {
val v = currentFocus
if (isShouldHideInput(v, ev)) { //点击editText控件外部
val imm: InputMethodManager =
getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
if (imm != null) {
assert(v != null)
hideInput(this)
if (editText != null) {
editText!!.clearFocus()
}
}
}
return super.dispatchTouchEvent(ev)
}
// 必不可少,否则所有的组件都不会有TouchEvent了
return window.superDispatchTouchEvent(ev) || onTouchEvent(ev)
}
fun isShouldHideInput(v: View?, event: MotionEvent): Boolean {
if (v != null && v is EditText) {
editText = v
val leftTop = intArrayOf(0, 0)
//获取输入框当前的location位置
v.getLocationInWindow(leftTop)
val left = leftTop[0]
val top = leftTop[1]
val bottom = top + v.getHeight()
val right = left + v.getWidth()
return !(event.x > left && event.x < right && event.y > top && event.y < bottom)
}
return false
}
/**
* 隐藏键盘
*/
fun hideInput(activity: Activity) {
val imm = MyApplication.context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
val v: View ?= activity.window.peekDecorView()
if (null != v) {
imm.hideSoftInputFromWindow(v.windowToken, 0)
}
}
}