一、自动弹出键盘或是自动不弹出

在进入界面时,有时会需要自动弹出键盘,实现方式如下:

    1. 在清单文件中设置android:windowSoftInputMode属性 ``` 在 AndroidManifest.xml文件中的activity节点下添加: android:windowSoftInputMode=”stateHidden|adjustPan”

stateVisibile:显示键盘 stateHidden:是隐藏软键盘的

adjustPan:是保证控件不会因为输入法的弹出而发生形变的。 adjustResize: 会因为弹出键盘调整布局

  1. - 2. 代码中调用 setSoftInputMode()方法进行设置

OnCreate方法里面加下面这句代码 ,很管用,而且再点EditBox也能让输入法正常弹出。。 getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

  1. <a name="7Qbeh"></a>
  2. ## 二、键盘遮挡布局处理
  3. <a name="MJCV3"></a>
  4. #### 2.1 对于非滚动布局
  5. - 如果设置了adjustResize,键盘会顶起整个界面
  6. 没有键盘时的界面:<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/1624725/1604849402465-13bc035c-5530-4916-a893-9693da935654.png#align=left&display=inline&height=493&margin=%5Bobject%20Object%5D&name=image.png&originHeight=986&originWidth=628&size=52663&status=done&style=none&width=314)<br />有了键盘后的界面:<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/1624725/1604849424905-97c166e2-ed53-49d3-8c65-13b1d9d8e32b.png#align=left&display=inline&height=510&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1020&originWidth=614&size=72580&status=done&style=none&width=307)<br />处理方法:<br />在没有滚动布局时,尽量设置不改动界面布局,在清单文件中设置adjustPan,保证布局完整性。
  7. <a name="z80OV"></a>
  8. ### 2.2 在滚动布局中时
  9. - 1. 无论设置了 adjustPan 或是 adjustResize,都可以做到顶起布局,键盘不会挡到输入的文字。但是效果却不一样,下面是 adjustPan的效果:
  10. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/1624725/1605452047339-b291c87e-c3e5-480e-9c2b-ca5504fae52e.png#align=left&display=inline&height=521&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1042&originWidth=616&size=62985&status=done&style=none&width=308)<br />会将整个布局顶起。
  11. - 2. adjustResize 效果,不会顶起标题。
  12. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/1624725/1605452683385-17a26bed-6e18-4b66-819c-8ccb30e01068.png#align=left&display=inline&height=523&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1046&originWidth=616&size=66100&status=done&style=none&width=308)
  13. <a name="Lcgng"></a>
  14. ## 三、封装工具的使用

showSoftInput : 显示软键盘 hideSoftInput : 隐藏软键盘 toggleSoftInput : 切换键盘显示与否状态 isSoftInputVisible : 判断软键盘是否可见 registerSoftInputChangedListener : 注册软键盘改变监听器 unregisterSoftInputChangedListener: 注销软键盘改变监听器 fixAndroidBug5497 : 修复安卓 5497 BUG fixSoftInputLeaks : 修复软键盘内存泄漏 clickBlankArea2HideSoftInput : 点击屏幕空白区域隐藏软键盘 setSoftInputAdjustNothing : 软键盘以覆盖当前界面的形式出现 setSoftInputAdjustResize : 软键盘以顶起当前界面的形式出现, 注意这种方式会使得当前布局的高度发生变化,触发当前布局onSizeChanged方法回调,这里前后高度差就是软键盘的高度了 setSoftInputAdjustPan : 软键盘以上推当前界面的形式出现, 注意这种方式不会改变布局的高度 onDisableBackKeyDown : 禁用物理返回键 dispatchTouchEvent : 点击屏幕空白区域隐藏软键盘

  1. 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(

      1. InputMethodManager.SHOW_FORCED,
      2. InputMethodManager.HIDE_IMPLICIT_ONLY

      ) }

      /**

    • Show the soft input. */ fun showSoftInput(activity: Activity) { if (!isSoftInputVisible(activity)) {

      1. 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 =
      1. LUtilsConfig.getContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager ?: return
      view.isFocusable = true view.isFocusableInTouchMode = true view.requestFocus() imm.showSoftInput(view, flags, object : ResultReceiver(Handler()) {
      1. override fun onReceiveResult(resultCode: Int, resultData: Bundle) {
      2. if (resultCode == InputMethodManager.RESULT_UNCHANGED_HIDDEN
      3. || resultCode == InputMethodManager.RESULT_HIDDEN
      4. ) {
      5. toggleSoftInput()
      6. }
      7. }
      }) imm.toggleSoftInput(
      1. InputMethodManager.SHOW_FORCED,
      2. InputMethodManager.HIDE_IMPLICIT_ONLY
      ) }
  1. /**
  2. * Toggle the soft input display or not.即使已经显示了键盘,调用以后会先隐藏键盘再显示
  3. */
  4. fun toggleSoftInput() {
  5. val imm =
  6. LUtilsConfig.getContext()
  7. .getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
  8. ?: return
  9. imm.toggleSoftInput(0, 0)
  10. }
  11. /**
  12. * Hide the soft input.
  13. *
  14. * @param activity The activity.
  15. */
  16. fun hideSoftInputByToggle(activity: Activity?) {
  17. val nowMillis = SystemClock.elapsedRealtime()
  18. val delta = nowMillis - millis
  19. if (Math.abs(delta) > 500 && isSoftInputVisible(activity!!)) {
  20. toggleSoftInput()
  21. }
  22. millis = nowMillis
  23. }
  24. /**
  25. * Hide the soft input.
  26. *
  27. * @param activity The activity.
  28. */
  29. fun hideSoftInput(activity: Activity) {
  30. hideSoftInput(activity.window)
  31. }
  32. /**
  33. * Hide the soft input.
  34. *
  35. * @param window The window.
  36. */
  37. fun hideSoftInput(window: Window) {
  38. var view = window.currentFocus
  39. if (view == null) {
  40. val decorView = window.decorView
  41. val focusView =
  42. decorView.findViewWithTag<View>("keyboardTagView")
  43. if (focusView == null) {
  44. view = EditText(window.context)
  45. view.setTag("keyboardTagView")
  46. (decorView as ViewGroup).addView(view, 0, 0)
  47. } else {
  48. view = focusView
  49. }
  50. view.requestFocus()
  51. }
  52. hideSoftInput(view)
  53. }
  54. /**
  55. * Hide the soft input.
  56. *
  57. * @param view The view.
  58. */
  59. fun hideSoftInput(view: View?) {
  60. if (view == null) return
  61. val imm =
  62. LUtilsConfig.getContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
  63. ?: return
  64. imm.hideSoftInputFromWindow(view.windowToken, 0)
  65. }
  66. /**
  67. * Return whether soft input is visible.
  68. *
  69. * @param activity The activity.
  70. * @return `true`: yes<br></br>`false`: no
  71. */
  72. fun isSoftInputVisible(activity: Activity): Boolean {
  73. return getDecorViewInvisibleHeight(activity.window) > 0
  74. }
  75. private fun getDecorViewInvisibleHeight(window: Window): Int {
  76. val decorView = window.decorView
  77. val outRect = Rect()
  78. decorView.getWindowVisibleDisplayFrame(outRect)
  79. val delta = Math.abs(decorView.bottom - outRect.bottom)
  80. if (delta <= UtilsBridge.getNavBarHeight() + UtilsBridge.getStatusBarHeight()) {
  81. sDecorViewDelta = delta
  82. return 0
  83. }
  84. return delta - sDecorViewDelta
  85. }
  86. /**
  87. * Register soft input changed listener.
  88. *
  89. * @param activity The activity.
  90. * @param listener The soft input changed listener.
  91. */
  92. fun registerSoftInputChangedListener(
  93. activity: Activity,
  94. listener: OnSoftInputChangedListener
  95. ) {
  96. registerSoftInputChangedListener(activity.window, listener)
  97. }
  98. /**
  99. * Register soft input changed listener.
  100. *
  101. * @param window The window.
  102. * @param listener The soft input changed listener.
  103. */
  104. fun registerSoftInputChangedListener(
  105. window: Window,
  106. listener: OnSoftInputChangedListener
  107. ) {
  108. val flags = window.attributes.flags
  109. if (flags and WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS != 0) {
  110. window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
  111. }
  112. val contentView = window.findViewById<FrameLayout>(R.id.content)
  113. val decorViewInvisibleHeightPre =
  114. intArrayOf(getDecorViewInvisibleHeight(window))
  115. val onGlobalLayoutListener = OnGlobalLayoutListener {
  116. val height = getDecorViewInvisibleHeight(window)
  117. if (decorViewInvisibleHeightPre[0] != height) {
  118. listener.onSoftInputChanged(height)
  119. decorViewInvisibleHeightPre[0] = height
  120. }
  121. }
  122. contentView.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener)
  123. contentView.setTag(TAG_ON_GLOBAL_LAYOUT_LISTENER, onGlobalLayoutListener)
  124. }
  125. /**
  126. * Unregister soft input changed listener.
  127. *
  128. * @param window The window.
  129. */
  130. fun unregisterSoftInputChangedListener(window: Window) {
  131. val contentView =
  132. window.findViewById<View>(R.id.content) ?: return
  133. val tag = contentView.getTag(TAG_ON_GLOBAL_LAYOUT_LISTENER)
  134. if (tag is OnGlobalLayoutListener) {
  135. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
  136. contentView.viewTreeObserver
  137. .removeOnGlobalLayoutListener(tag)
  138. }
  139. }
  140. }
  141. /**
  142. * Fix the bug of 5497 in Android.
  143. *
  144. * Don't set adjustResize
  145. *
  146. * @param activity The activity.
  147. */
  148. fun fixAndroidBug5497(activity: Activity) {
  149. fixAndroidBug5497(activity.window)
  150. }
  151. /**
  152. * Fix the bug of 5497 in Android.
  153. *
  154. * It will clean the adjustResize
  155. *
  156. * @param window The window.
  157. */
  158. fun fixAndroidBug5497(window: Window) {
  159. val softInputMode = window.attributes.softInputMode
  160. window.setSoftInputMode(softInputMode and WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE.inv())
  161. val contentView = window.findViewById<FrameLayout>(R.id.content)
  162. val contentViewChild = contentView.getChildAt(0)
  163. val paddingBottom = contentViewChild.paddingBottom
  164. val contentViewInvisibleHeightPre5497 =
  165. intArrayOf(getContentViewInvisibleHeight(window))
  166. contentView.viewTreeObserver
  167. .addOnGlobalLayoutListener {
  168. val height = getContentViewInvisibleHeight(window)
  169. if (contentViewInvisibleHeightPre5497[0] != height) {
  170. contentViewChild.setPadding(
  171. contentViewChild.paddingLeft,
  172. contentViewChild.paddingTop,
  173. contentViewChild.paddingRight,
  174. paddingBottom + getDecorViewInvisibleHeight(window)
  175. )
  176. contentViewInvisibleHeightPre5497[0] = height
  177. }
  178. }
  179. }
  180. private fun getContentViewInvisibleHeight(window: Window): Int {
  181. val contentView =
  182. window.findViewById<View>(R.id.content) ?: return 0
  183. val outRect = Rect()
  184. contentView.getWindowVisibleDisplayFrame(outRect)
  185. Log.d(
  186. "KeyboardUtils", "getContentViewInvisibleHeight: "
  187. + (contentView.bottom - outRect.bottom)
  188. )
  189. val delta = Math.abs(contentView.bottom - outRect.bottom)
  190. return if (delta <= UtilsBridge.getStatusBarHeight() + UtilsBridge.getNavBarHeight()) {
  191. 0
  192. } else delta
  193. }
  194. /**
  195. * Fix the leaks of soft input.
  196. *
  197. * @param activity The activity.
  198. */
  199. fun fixSoftInputLeaks(activity: Activity) {
  200. fixSoftInputLeaks(activity.window)
  201. }
  202. /**
  203. * Fix the leaks of soft input.
  204. *
  205. * @param window The window.
  206. */
  207. fun fixSoftInputLeaks(window: Window) {
  208. val imm =
  209. LUtilsConfig.getContext()
  210. .getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
  211. ?: return
  212. val leakViews =
  213. arrayOf("mLastSrvView", "mCurRootView", "mServedView", "mNextServedView")
  214. for (leakView in leakViews) {
  215. try {
  216. val leakViewField =
  217. InputMethodManager::class.java.getDeclaredField(
  218. leakView
  219. )
  220. if (!leakViewField.isAccessible) {
  221. leakViewField.isAccessible = true
  222. }
  223. val obj = leakViewField[imm] as? View ?: continue
  224. if (obj.rootView === window.decorView.rootView) {
  225. leakViewField[imm] = null
  226. }
  227. } catch (ignore: Throwable) { /**/
  228. }
  229. }
  230. }
  231. // interface
  232. ///////////////////////////////////////////////////////////////////////////
  233. interface OnSoftInputChangedListener {
  234. fun onSoftInputChanged(height: Int)
  235. }
  236. /**
  237. * 软键盘以覆盖当前界面的形式出现
  238. *
  239. * @param activity
  240. */
  241. fun setSoftInputAdjustNothing(activity: Activity) {
  242. activity.window.setSoftInputMode(
  243. WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
  244. or WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN
  245. )
  246. }
  247. /**
  248. * 软键盘以顶起当前界面的形式出现, 注意这种方式会使得当前布局的高度发生变化,触发当前布局onSizeChanged方法回调,这里前后高度差就是软键盘的高度了
  249. *
  250. * @param activity
  251. */
  252. fun setSoftInputAdjustResize(activity: Activity) {
  253. activity.window.setSoftInputMode(
  254. WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
  255. or WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN
  256. )
  257. }
  258. /**
  259. * 软键盘以上推当前界面的形式出现, 注意这种方式不会改变布局的高度
  260. *
  261. * @param activity
  262. */
  263. fun setSoftInputAdjustPan(activity: Activity) {
  264. activity.window.setSoftInputMode(
  265. WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
  266. or WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN
  267. )
  268. }
  269. /**
  270. * 禁用物理返回键
  271. *
  272. *
  273. * 使用方法:
  274. *
  275. * 需重写 onKeyDown
  276. *
  277. * @param keyCode
  278. * @return
  279. * @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
  280. * return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event) ;
  281. * }
  282. */
  283. fun onDisableBackKeyDown(keyCode: Int): Boolean {
  284. when (keyCode) {
  285. KeyEvent.KEYCODE_BACK -> return false
  286. KeyEvent.KEYCODE_HOME -> return false
  287. else -> {
  288. }
  289. }
  290. return true
  291. }
  292. /**
  293. * 点击屏幕空白区域隐藏软键盘
  294. *
  295. * 根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘
  296. *
  297. * 需重写 dispatchTouchEvent
  298. *
  299. * @param ev
  300. * @param activity 窗口
  301. * @return
  302. */
  303. fun dispatchTouchEvent(ev: MotionEvent?, activity: Activity) {
  304. if (ev == null) return
  305. if (ev.action == MotionEvent.ACTION_DOWN) {
  306. val v = activity.currentFocus
  307. if (isShouldHideKeyboard(v, ev)) {
  308. hideSoftInput(v)
  309. }
  310. }
  311. }
  312. /**
  313. * 点击屏幕空白区域隐藏软键盘
  314. *
  315. * 根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘
  316. *
  317. * 需重写 dispatchTouchEvent
  318. *
  319. * @param ev
  320. * @param dialog 窗口
  321. * @return
  322. */
  323. fun dispatchTouchEvent(ev: MotionEvent?, dialog: Dialog) {
  324. if (ev == null) return
  325. if (ev.action == MotionEvent.ACTION_DOWN) {
  326. val v = dialog.currentFocus
  327. if (isShouldHideKeyboard(v, ev)) {
  328. hideSoftInput(v)
  329. }
  330. }
  331. }
  332. /**
  333. * 点击屏幕空白区域隐藏软键盘
  334. *
  335. * 根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘
  336. *
  337. * 需重写 dispatchTouchEvent
  338. *
  339. * @param ev
  340. * @param focusView 聚焦的view
  341. * @return
  342. */
  343. fun dispatchTouchEvent(ev: MotionEvent?, focusView: View?) {
  344. if (ev == null) return
  345. if (ev.action == MotionEvent.ACTION_DOWN) {
  346. if (isShouldHideKeyboard(focusView, ev)) {
  347. hideSoftInput(focusView)
  348. }
  349. }
  350. }
  351. /**
  352. * 点击屏幕空白区域隐藏软键盘
  353. *
  354. * 根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘
  355. *
  356. * 需重写 dispatchTouchEvent
  357. *
  358. * @param ev
  359. * @param window 窗口
  360. * @return
  361. */
  362. fun dispatchTouchEvent(ev: MotionEvent?, window: Window) {
  363. if (ev == null) return
  364. if (ev.action == MotionEvent.ACTION_DOWN) {
  365. val v = window.currentFocus
  366. if (isShouldHideKeyboard(v, ev)) {
  367. hideSoftInput(v)
  368. }
  369. }
  370. }
  371. /**
  372. * 根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘
  373. *
  374. * @param v
  375. * @param event
  376. * @return
  377. */
  378. private fun isShouldHideKeyboard(v: View?, event: MotionEvent): Boolean {
  379. if (v != null && v is EditText) {
  380. val l = intArrayOf(0, 0)
  381. v.getLocationInWindow(l)
  382. val left = l[0]
  383. val top = l[1]
  384. val bottom = top + v.getHeight()
  385. val right = left + v.getWidth()
  386. return !(event.x > left && event.x < right && event.y > top && event.y < bottom)
  387. }
  388. return false
  389. }

}

  1. UtilsBridge:

object UtilsBridge { val statusBarHeight: Int get() { val resources = getContext().resources val resourceId = resources.getIdentifier(“status_bar_height”, “dimen”, “android”) return resources.getDimensionPixelSize(resourceId) }

  1. val navBarHeight: Int
  2. get() {
  3. val res =
  4. getContext().resources
  5. val resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android")
  6. return if (resourceId != 0) {
  7. res.getDimensionPixelSize(resourceId)
  8. } else {
  9. 0
  10. }
  11. }

} ```