一、自动弹出键盘或是自动不弹出
在进入界面时,有时会需要自动弹出键盘,实现方式如下:
- 在清单文件中设置android:windowSoftInputMode属性 ``` 在 AndroidManifest.xml文件中的activity节点下添加: android:windowSoftInputMode=”stateHidden|adjustPan”
stateVisibile:显示键盘 stateHidden:是隐藏软键盘的
adjustPan:是保证控件不会因为输入法的弹出而发生形变的。 adjustResize: 会因为弹出键盘调整布局
- 2. 代码中调用 setSoftInputMode()方法进行设置
OnCreate方法里面加下面这句代码 ,很管用,而且再点EditBox也能让输入法正常弹出。。 getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
<a name="7Qbeh"></a>## 二、键盘遮挡布局处理<a name="MJCV3"></a>#### 2.1 对于非滚动布局- 如果设置了adjustResize,键盘会顶起整个界面没有键盘时的界面:<br /><br />有了键盘后的界面:<br /><br />处理方法:<br />在没有滚动布局时,尽量设置不改动界面布局,在清单文件中设置adjustPan,保证布局完整性。<a name="z80OV"></a>### 2.2 在滚动布局中时- 1. 无论设置了 adjustPan 或是 adjustResize,都可以做到顶起布局,键盘不会挡到输入的文字。但是效果却不一样,下面是 adjustPan的效果:<br />会将整个布局顶起。- 2. adjustResize 效果,不会顶起标题。<a name="Lcgng"></a>## 三、封装工具的使用
showSoftInput : 显示软键盘 hideSoftInput : 隐藏软键盘 toggleSoftInput : 切换键盘显示与否状态 isSoftInputVisible : 判断软键盘是否可见 registerSoftInputChangedListener : 注册软键盘改变监听器 unregisterSoftInputChangedListener: 注销软键盘改变监听器 fixAndroidBug5497 : 修复安卓 5497 BUG fixSoftInputLeaks : 修复软键盘内存泄漏 clickBlankArea2HideSoftInput : 点击屏幕空白区域隐藏软键盘 setSoftInputAdjustNothing : 软键盘以覆盖当前界面的形式出现 setSoftInputAdjustResize : 软键盘以顶起当前界面的形式出现, 注意这种方式会使得当前布局的高度发生变化,触发当前布局onSizeChanged方法回调,这里前后高度差就是软键盘的高度了 setSoftInputAdjustPan : 软键盘以上推当前界面的形式出现, 注意这种方式不会改变布局的高度 onDisableBackKeyDown : 禁用物理返回键 dispatchTouchEvent : 点击屏幕空白区域隐藏软键盘
KeyboardUtils:
package com.kiwilss.lutils.res
import android.R import android.app.Activity import android.app.Dialog import android.content.Context import android.graphics.Rect import android.os. import android.util.Log import android.view. import android.view.ViewTreeObserver.OnGlobalLayoutListener import android.view.inputmethod.InputMethodManager import android.widget.EditText import android.widget.FrameLayout import com.kiwilss.lutils.LUtilsConfig
/* @FileName: KeyboardUtils *@author : Lss kiwilss
- @e-mail : kiwilss@163.com
- @time : 2020/11/15
@desc : {DESCRIPTION} */ object KeyboardUtils { private var millis: Long = 0 private var sDecorViewDelta = 0 private const val TAG_ON_GLOBAL_LAYOUT_LISTENER = -8
//显示软键盘相关 /**
Show the soft input. */ fun showSoftInput() { val imm = LUtilsConfig.getContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager ?: return imm.toggleSoftInput(
InputMethodManager.SHOW_FORCED,InputMethodManager.HIDE_IMPLICIT_ONLY
) }
/**
Show the soft input. */ fun showSoftInput(activity: Activity) { if (!isSoftInputVisible(activity)) {
toggleSoftInput()
} }
/**
- Show the soft input. *
@param view The view. */ fun showSoftInput(view: View) { showSoftInput(view, 0) }
/**
- Show the soft input. *
- @param view The view.
- @param flags Provides additional operating flags. Currently may be
- 0 or have the [InputMethodManager.SHOW_IMPLICIT] bit set.
*/
fun showSoftInput(view: View, flags: Int) {
val imm =
view.isFocusable = true view.isFocusableInTouchMode = true view.requestFocus() imm.showSoftInput(view, flags, object : ResultReceiver(Handler()) {LUtilsConfig.getContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager ?: return
}) imm.toggleSoftInput(override fun onReceiveResult(resultCode: Int, resultData: Bundle) {if (resultCode == InputMethodManager.RESULT_UNCHANGED_HIDDEN|| resultCode == InputMethodManager.RESULT_HIDDEN) {toggleSoftInput()}}
) }InputMethodManager.SHOW_FORCED,InputMethodManager.HIDE_IMPLICIT_ONLY
/*** Toggle the soft input display or not.即使已经显示了键盘,调用以后会先隐藏键盘再显示*/fun toggleSoftInput() {val imm =LUtilsConfig.getContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager?: returnimm.toggleSoftInput(0, 0)}/*** Hide the soft input.** @param activity The activity.*/fun hideSoftInputByToggle(activity: Activity?) {val nowMillis = SystemClock.elapsedRealtime()val delta = nowMillis - millisif (Math.abs(delta) > 500 && isSoftInputVisible(activity!!)) {toggleSoftInput()}millis = nowMillis}/*** Hide the soft input.** @param activity The activity.*/fun hideSoftInput(activity: Activity) {hideSoftInput(activity.window)}/*** Hide the soft input.** @param window The window.*/fun hideSoftInput(window: Window) {var view = window.currentFocusif (view == null) {val decorView = window.decorViewval focusView =decorView.findViewWithTag<View>("keyboardTagView")if (focusView == null) {view = EditText(window.context)view.setTag("keyboardTagView")(decorView as ViewGroup).addView(view, 0, 0)} else {view = focusView}view.requestFocus()}hideSoftInput(view)}/*** Hide the soft input.** @param view The view.*/fun hideSoftInput(view: View?) {if (view == null) returnval imm =LUtilsConfig.getContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager?: returnimm.hideSoftInputFromWindow(view.windowToken, 0)}/*** Return whether soft input is visible.** @param activity The activity.* @return `true`: yes<br></br>`false`: no*/fun isSoftInputVisible(activity: Activity): Boolean {return getDecorViewInvisibleHeight(activity.window) > 0}private fun getDecorViewInvisibleHeight(window: Window): Int {val decorView = window.decorViewval outRect = Rect()decorView.getWindowVisibleDisplayFrame(outRect)val delta = Math.abs(decorView.bottom - outRect.bottom)if (delta <= UtilsBridge.getNavBarHeight() + UtilsBridge.getStatusBarHeight()) {sDecorViewDelta = deltareturn 0}return delta - sDecorViewDelta}/*** Register soft input changed listener.** @param activity The activity.* @param listener The soft input changed listener.*/fun registerSoftInputChangedListener(activity: Activity,listener: OnSoftInputChangedListener) {registerSoftInputChangedListener(activity.window, listener)}/*** Register soft input changed listener.** @param window The window.* @param listener The soft input changed listener.*/fun registerSoftInputChangedListener(window: Window,listener: OnSoftInputChangedListener) {val flags = window.attributes.flagsif (flags and WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS != 0) {window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)}val contentView = window.findViewById<FrameLayout>(R.id.content)val decorViewInvisibleHeightPre =intArrayOf(getDecorViewInvisibleHeight(window))val onGlobalLayoutListener = OnGlobalLayoutListener {val height = getDecorViewInvisibleHeight(window)if (decorViewInvisibleHeightPre[0] != height) {listener.onSoftInputChanged(height)decorViewInvisibleHeightPre[0] = height}}contentView.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener)contentView.setTag(TAG_ON_GLOBAL_LAYOUT_LISTENER, onGlobalLayoutListener)}/*** Unregister soft input changed listener.** @param window The window.*/fun unregisterSoftInputChangedListener(window: Window) {val contentView =window.findViewById<View>(R.id.content) ?: returnval tag = contentView.getTag(TAG_ON_GLOBAL_LAYOUT_LISTENER)if (tag is OnGlobalLayoutListener) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {contentView.viewTreeObserver.removeOnGlobalLayoutListener(tag)}}}/*** Fix the bug of 5497 in Android.** Don't set adjustResize** @param activity The activity.*/fun fixAndroidBug5497(activity: Activity) {fixAndroidBug5497(activity.window)}/*** Fix the bug of 5497 in Android.** It will clean the adjustResize** @param window The window.*/fun fixAndroidBug5497(window: Window) {val softInputMode = window.attributes.softInputModewindow.setSoftInputMode(softInputMode and WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE.inv())val contentView = window.findViewById<FrameLayout>(R.id.content)val contentViewChild = contentView.getChildAt(0)val paddingBottom = contentViewChild.paddingBottomval contentViewInvisibleHeightPre5497 =intArrayOf(getContentViewInvisibleHeight(window))contentView.viewTreeObserver.addOnGlobalLayoutListener {val height = getContentViewInvisibleHeight(window)if (contentViewInvisibleHeightPre5497[0] != height) {contentViewChild.setPadding(contentViewChild.paddingLeft,contentViewChild.paddingTop,contentViewChild.paddingRight,paddingBottom + getDecorViewInvisibleHeight(window))contentViewInvisibleHeightPre5497[0] = height}}}private fun getContentViewInvisibleHeight(window: Window): Int {val contentView =window.findViewById<View>(R.id.content) ?: return 0val outRect = Rect()contentView.getWindowVisibleDisplayFrame(outRect)Log.d("KeyboardUtils", "getContentViewInvisibleHeight: "+ (contentView.bottom - outRect.bottom))val delta = Math.abs(contentView.bottom - outRect.bottom)return if (delta <= UtilsBridge.getStatusBarHeight() + UtilsBridge.getNavBarHeight()) {0} else delta}/*** Fix the leaks of soft input.** @param activity The activity.*/fun fixSoftInputLeaks(activity: Activity) {fixSoftInputLeaks(activity.window)}/*** Fix the leaks of soft input.** @param window The window.*/fun fixSoftInputLeaks(window: Window) {val imm =LUtilsConfig.getContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager?: returnval leakViews =arrayOf("mLastSrvView", "mCurRootView", "mServedView", "mNextServedView")for (leakView in leakViews) {try {val leakViewField =InputMethodManager::class.java.getDeclaredField(leakView)if (!leakViewField.isAccessible) {leakViewField.isAccessible = true}val obj = leakViewField[imm] as? View ?: continueif (obj.rootView === window.decorView.rootView) {leakViewField[imm] = null}} catch (ignore: Throwable) { /**/}}}// interface///////////////////////////////////////////////////////////////////////////interface OnSoftInputChangedListener {fun onSoftInputChanged(height: Int)}/*** 软键盘以覆盖当前界面的形式出现** @param activity*/fun setSoftInputAdjustNothing(activity: Activity) {activity.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHINGor WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)}/*** 软键盘以顶起当前界面的形式出现, 注意这种方式会使得当前布局的高度发生变化,触发当前布局onSizeChanged方法回调,这里前后高度差就是软键盘的高度了** @param activity*/fun setSoftInputAdjustResize(activity: Activity) {activity.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZEor WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)}/*** 软键盘以上推当前界面的形式出现, 注意这种方式不会改变布局的高度** @param activity*/fun setSoftInputAdjustPan(activity: Activity) {activity.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PANor WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)}/*** 禁用物理返回键*** 使用方法:** 需重写 onKeyDown** @param keyCode* @return* @Override public boolean onKeyDown(int keyCode, KeyEvent event) {* return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event) ;* }*/fun onDisableBackKeyDown(keyCode: Int): Boolean {when (keyCode) {KeyEvent.KEYCODE_BACK -> return falseKeyEvent.KEYCODE_HOME -> return falseelse -> {}}return true}/*** 点击屏幕空白区域隐藏软键盘** 根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘** 需重写 dispatchTouchEvent** @param ev* @param activity 窗口* @return*/fun dispatchTouchEvent(ev: MotionEvent?, activity: Activity) {if (ev == null) returnif (ev.action == MotionEvent.ACTION_DOWN) {val v = activity.currentFocusif (isShouldHideKeyboard(v, ev)) {hideSoftInput(v)}}}/*** 点击屏幕空白区域隐藏软键盘** 根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘** 需重写 dispatchTouchEvent** @param ev* @param dialog 窗口* @return*/fun dispatchTouchEvent(ev: MotionEvent?, dialog: Dialog) {if (ev == null) returnif (ev.action == MotionEvent.ACTION_DOWN) {val v = dialog.currentFocusif (isShouldHideKeyboard(v, ev)) {hideSoftInput(v)}}}/*** 点击屏幕空白区域隐藏软键盘** 根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘** 需重写 dispatchTouchEvent** @param ev* @param focusView 聚焦的view* @return*/fun dispatchTouchEvent(ev: MotionEvent?, focusView: View?) {if (ev == null) returnif (ev.action == MotionEvent.ACTION_DOWN) {if (isShouldHideKeyboard(focusView, ev)) {hideSoftInput(focusView)}}}/*** 点击屏幕空白区域隐藏软键盘** 根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘** 需重写 dispatchTouchEvent** @param ev* @param window 窗口* @return*/fun dispatchTouchEvent(ev: MotionEvent?, window: Window) {if (ev == null) returnif (ev.action == MotionEvent.ACTION_DOWN) {val v = window.currentFocusif (isShouldHideKeyboard(v, ev)) {hideSoftInput(v)}}}/*** 根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘** @param v* @param event* @return*/private fun isShouldHideKeyboard(v: View?, event: MotionEvent): Boolean {if (v != null && v is EditText) {val l = intArrayOf(0, 0)v.getLocationInWindow(l)val left = l[0]val top = l[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}
}
UtilsBridge:
object UtilsBridge { val statusBarHeight: Int get() { val resources = getContext().resources val resourceId = resources.getIdentifier(“status_bar_height”, “dimen”, “android”) return resources.getDimensionPixelSize(resourceId) }
val navBarHeight: Intget() {val res =getContext().resourcesval resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android")return if (resourceId != 0) {res.getDimensionPixelSize(resourceId)} else {0}}
} ```
