软键盘问题整理
Posted 且听真言
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了软键盘问题整理相关的知识,希望对你有一定的参考价值。
最近开发中遇到了一些软键盘相关的问题,所以整理下与大家分享:
一、软键盘的开启与关闭
开启:
1、获取InputMethodManager 实例。
2、调用showSoftInput()方法。
fun showSoftInput(view: View?)
view?.let
val inputMethodManager =
it.context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
inputMethodManager?.showSoftInput(it, 0)
/**
* Synonym for @link #showSoftInput(View, int, ResultReceiver) without
* a result receiver: explicitly request that the current input method's
* soft input area be shown to the user, if needed.
*
* @param view The currently focused view, which would like to receive
* soft keyboard input.
* @param flags Provides additional operating flags. Currently may be
* 0 or have the @link #SHOW_IMPLICIT bit set.
*/
public boolean showSoftInput(View view, int flags)
// Re-dispatch if there is a context mismatch.
final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
if (fallbackImm != null)
return fallbackImm.showSoftInput(view, flags);
return showSoftInput(view, flags, null);
showSoftInput需要两个参数,第一个类型是View类型,最好是一个EditText或者其子类,
注意:如果传入的View不是一个EditText,那么这个View必须有两个属性:android:focusable="true" 和 android:focusableInTouchMode="true"。
第二个参数是flags就是个标志位,flags可以是0、或者是SHOW_IMPLICIT、SHOW_FORCED。
/**
* Flag for @link #showSoftInput to indicate that this is an implicit
* request to show the input window, not as the result of a direct request
* by the user. The window may not be shown in this case.
*/
public static final int SHOW_IMPLICIT = 0x0001;
/**
* Flag for @link #showSoftInput to indicate that the user has forced
* the input method open (such as by long-pressing menu) so it should
* not be closed until they explicitly do so.
*/
public static final int SHOW_FORCED = 0x0002;
一个非EditText如何打开和关闭软键盘示例:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TesSoftInputActivity">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/soft_input_open_btn"
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center"
android:text="打开软键盘"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/soft_input_close_btn"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="关闭软键盘"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/soft_input_open_btn" />
<EditText
android:layout_width="match_parent"
android:layout_height="200dp"
android:paddingBottom="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.example.myapplication
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.view.inputmethod.InputMethodManager
class TesSoftInputActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_tes_soft_input)
val softInpuBtn = findViewById<View>(R.id.soft_input_open_btn)
softInpuBtn.isFocusable = true
softInpuBtn.isFocusableInTouchMode = true
softInpuBtn.requestFocus()
softInpuBtn.setOnClickListener
showSoftInput(it)
val softCloseBtn = findViewById<View>(R.id.soft_input_close_btn)
softCloseBtn.setOnClickListener
hideSoftInput(it)
private fun showSoftInput(view: View?)
view?.let
val inputMethodManager =
it.context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
inputMethodManager?.showSoftInput(it, 0)
private fun hideSoftInput(view: View?)
view?.let
val inputMethodManager =
it.context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
inputMethodManager?.hideSoftInputFromWindow(it.windowToken, 0)
关闭
1、获取InputMethodManager 实例。
2、调用hideSoftInputFromWindow()方法。
fun hideSoftInput(view: View?)
view?.let
val inputMethodManager =
it.context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
inputMethodManager?.hideSoftInputFromWindow(it.windowToken, 0)
二、如何获取软键盘的高度
Activity窗口的构成:当软键盘弹出时,软键盘会覆盖内容区域,剩余的区域就是可见区域。
只需要将屏幕高度-可见区域的高度,就是软键盘的高度。
Rect 类
public int left;
public int top;
public int right;
public int bottom;
这4个属性描述着这一个“方块”,如下图:
Rect最左侧到屏幕的左侧的距离是 left
Rect最上面到屏幕上方的距离是 top
Rect最右侧到屏幕左侧的距离是 right
Rect最下面到屏幕上方的距离是 bottom
通过 长方形4个点的坐标,可以计算出这个长方形的尺寸
长 = bottom - top
宽 = right - left
package com.example.myapplication
import android.content.Context
import android.graphics.Rect
import android.util.Log
import android.view.View
/**
* Created by david on 2022/2/12.
* @author david
*/
class LiveSoftHelpUtil
companion object
const val TAG = "LiveSoftHelpUtil"
//记录软键盘的高度
private var mSoftInputHeight = 0
//底部NavigationBar的高度
private var mNavigationBarHeight = 0
//底部NavigationBar是否展示
private var mIsNavigationBarShow = false
//软键盘高度是否发生变化
private var mSoftInputHeightChanged = false
//软键盘改变回调
private var mSoftInputChangedListener: ISoftInputChanged? = null
//需要移动的EditTextView
private var mView: View? = null
//软键盘是否展示
private var mIsSoftInputShowing = false
interface ISoftInputChanged
//软键盘发生改变
fun onChanged(isSoftInputShow: Boolean, softInputHeight: Int, viewOffset: Int)
fun attachSoftInput(view: View? = null, listener: ISoftInputChanged? = null)
//获取根View
val rootView = view?.rootView ?: return
mNavigationBarHeight = getNavigationBarHeight(rootView.context)
this.mView = view
this.mSoftInputChangedListener = listener
rootView.addOnLayoutChangeListener(object : View.OnLayoutChangeListener
override fun onLayoutChange(
v: View?,
left: Int,
top: Int,
right: Int,
bottom: Int,
oldLeft: Int,
oldTop: Int,
oldRight: Int,
oldBottom: Int
)
//获取屏幕高度
val rootHeight = rootView.height
Log.v(TAG, "rootHeight:$rootHeight")
val rect = Rect()
//获取可见部分的高度(除状态栏和导航栏)
rootView.getWindowVisibleDisplayFrame(rect)
if (rootHeight - rect.bottom == mNavigationBarHeight)
//如果可见部分与屏幕底部刚好差值为导航栏的高度,则认为有导航栏
mIsNavigationBarShow = true
else if (rootHeight - rect.bottom == 0)
//如果可见部分与屏幕底部平齐,说明没有导航栏
mIsNavigationBarShow = false
//记录软键盘是否展示
var isSoftInputShow = false
//记录软键盘的高度
var softInputHeight = 0
//如果有导航栏,需要去除导航栏的高度
val mutableHeight = if (mIsNavigationBarShow) mNavigationBarHeight else 0
Log.v(TAG, "mNavigationBarHeight:$mNavigationBarHeight")
if (rootHeight - mutableHeight > rect.bottom)
//除去导航栏高度后,可见区域 小于 屏幕高度,说明软键盘弹起
isSoftInputShow = true
//键盘高度
softInputHeight = rootHeight - mutableHeight - rect.bottom
if (this@LiveSoftHelpUtil.mSoftInputHeight != softInputHeight)
mSoftInputHeightChanged = true
this@LiveSoftHelpUtil.mSoftInputHeight = softInputHeight
else
mSoftInputHeightChanged = false
//获取EditText坐标
val location = IntArray(2)
view.getLocationOnScreen(location)
if (mIsSoftInputShowing != isSoftInputShow || (isSoftInputShow && mSoftInputHeightChanged))
listener?.onChanged(
isSoftInputShow,
softInputHeight,
location[1] + view.height - rect.bottom
)
mIsSoftInputShowing = isSoftInputShow
)
/**
* 获取NavigationBar的高度
*/
private fun getNavigationBarHeight(context: Context): Int
val resources = context.resources
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
return resources.getDimensionPixelSize(resourceId)
三、WindowManager.LayoutParams.softInputMode(软键盘的模式)
public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
public static final int SOFT_INPUT_ADJUST_NOTHING = 0x30;
1.SOFT_INPUT_ADJUST_PAN 软键盘弹起,布局需要整体移动
设置softInputMode有两种方式:
1.代码设置:
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_soft_input_1)
window.attributes.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
... ...
2.xml设置:
<activity
android:name=".TesSoftInputActivity"
android:exported="true"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
效果:布局随着软键盘被顶上去。
2.SOFT_INPUT_ADJUST_UNSPECIFIED 不指定调整方式,系统自行决定使用哪种调整方式
window.attributes.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED
android:windowSoftInputMode="adjustUnspecified"
效果:布局随着软键盘被顶上去。
3.SOFT_INPUT_ADJUST_RESIZE
window.attributes.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
android:windowSoftInputMode="adjustResize"
效果:软键盘弹起,布局没有变动。
4.SOFT_INPUT_ADJUST_NOTHING
window.attributes.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
android:windowSoftInputMode="adjustNothing"
效果:软键盘弹起,布局没有变动。
修改布局观看SOFT_INPUT_ADJUST_RESIZE效果
window.attributes.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
修改方式:将ImageView填充满除EdItText以外的空间。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="@android:color/holo_blue_light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/et"/>
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/et"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:autofillHints="@string/hint"
android:focusable="true"
android:hint="@string/hint"
android:inputType="text"
android:textColor="@color/black"
android:textColorHint="@color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
效果:此时ImageView被压缩了,说明布局文件被重新计算大小。
修改布局观看SOFT_INPUT_ADJUST_UNSPECIFIED效果
ImageView里增加isScrollContainer 属性 android:isScrollContainer="true"
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:isScrollContainer="true"
android:background="@android:color/holo_blue_light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/et"/>
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/et"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:autofillHints="@string/hint"
android:focusable="true"
android:hint="@string/hint"
android:inputType="text"
android:textColor="@color/black"
android:textColorHint="@color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
可以看到SOFT_INPUT_ADJUST_UNSPECIFIED 模式下产生的效果可能与SOFT_INPUT_ADJUST_PAN相同,也可能与SOFT_INPUT_ADJUST_RESIZE相同。
以上是关于软键盘问题整理的主要内容,如果未能解决你的问题,请参考以下文章