监听点击SoftKeyboard外部区域来收起输入法的实现方法
在Android应用中,当用户点击屏幕上的非EditText区域时,通常希望自动隐藏软键盘以提供更好的用户体验。以下是几种常见的实现方式及其详细说明和代码示例。
方法1:使用OnTouchListener
监听触摸事件
这种方法通过设置一个全局的OnTouchListener
来监听整个窗口的触摸事件,并在检测到点击发生在当前焦点视图(通常是EditText)之外时隐藏输入法。
代码示例 (Kotlin):
kotlin 代码解读复制代码class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// 设置触摸监听器给根布局
findViewById(android.R.id.content).setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
val currentFocus = currentFocus
if (currentFocus is EditText && !isTouchInsideView(event, currentFocus)) {
hideSoftKeyboard(this, currentFocus)
return@setOnTouchListener true // 拦截事件
}
}
false
}
// 示例:点击按钮打开软键盘
binding.openKeyboardButton.setOnClickListener {
openSoftKeyboard(binding.etInputData)
}
}
/**
* 判断点击是否在指定视图内。
*/
private fun isTouchInsideView(event: MotionEvent, view: View): Boolean {
val location = IntArray(2)
view.getLocationOnScreen(location)
val left = location[0]
val top = location[1]
val right = left + view.width
val bottom = top + view.height
return event.rawX >= left && event.rawX <= right &&
event.rawY >= top && event.rawY <= bottom
}
/**
* 隐藏软键盘的方法。
*/
private fun hideSoftKeyboard(activity: Activity, view: View) {
val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
/**
* 打开软键盘的方法。
*/
private fun openSoftKeyboard(view: View) {
view.requestFocus()
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
}
}
方法2:重写dispatchTouchEvent
这个方法是在Activity中重写dispatchTouchEvent
方法,捕捉所有传入的触摸事件,并判断点击是否发生在EditText以外的区域。如果点击发生在EditText外,则隐藏输入法。
代码示例 (Kotlin):
kotlin 代码解读复制代码class KeyboardExampleActivity : AppCompatActivity() {
private lateinit var binding: ActivityKeyboardExampleBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityKeyboardExampleBinding.inflate(layoutInflater)
setContentView(binding.root)
// 其他初始化代码...
}
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
if (ev.action == MotionEvent.ACTION_DOWN) {
val currentFocusView = currentFocus
if (currentFocusView is EditText && !isTouchTargetView(ev, currentFocusView)) {
// 如果点击不是在当前获得焦点的EditText上,则隐藏软键盘
hideKeyboard(currentFocusView)
}
}
return super.dispatchTouchEvent(ev)
}
/**
* 判断手指落点是否位于输入框控件区域内。
*/
private fun isTouchTargetView(event: MotionEvent?, view: View?): Boolean {
if (event == null || view == null) return false
val location = IntArray(2)
view.getLocationOnScreen(location)
val left = location[0]
val top = location[1]
val right = left + view.width
val bottom = top + view.height
return event.rawX >= left && event.rawX <= right &&
event.rawY >= top && event.rawY <= bottom
}
/**
* 隐藏软键盘的方法。
*/
private fun hideKeyboard(view: View) {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
/**
* 打开软键盘的方法。
*/
private fun openKeyboard(view: View) {
view.requestFocus()
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
}
}
方法3:使用TouchDelegate
TouchDelegate
主要用于扩大某个子View的触摸范围,而不是直接用来处理输入法的收起。它允许你指定一个父容器和一个代理区域,使得用户点击代理区域内的任何位置都会触发子View的点击事件。这在某些特定场景下有用,但并不是处理点击外部区域隐藏输入法的最常用方法。
使用场景与代码示例 (Kotlin):
kotlin 代码解读复制代码// 找到需要扩大的子View以及其所在的父容器
val parent = findViewById(R.id.parent_layout)
val smallButton = findViewById(R.id.small_button)
// 创建一个矩形作为扩展后的触摸区域
val bounds = Rect()
smallButton.getHitRect(bounds)
bounds.top -= 50 // 向上扩展
bounds.left -= 50 // 向左扩展
bounds.bottom += 50 // 向下扩展
bounds.right += 50 // 向右扩展
// 创建并应用TouchDelegate
parent.touchDelegate = TouchDelegate(bounds, smallButton)
方法4:结合dispatchTouchEvent
和isTouchTargetView
这是方法2的一个具体实现,它通过重写dispatchTouchEvent
方法来检查手指落点是否位于输入框控件区域内,如果不是的话则隐藏软键盘。落在软键盘上的点击会被软键盘消耗掉,不会调用Activity
的dispatchTouchEvent
方法。
代码示例 (Kotlin):
kotlin 代码解读复制代码class KeyboardActivity : AppCompatActivity() {
private lateinit var binding: ActivityKeyboardBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityKeyboardBinding.inflate(layoutInflater)
setContentView(binding.root)
// 示例:点击按钮打开软键盘
binding.openKeyboardButton.setOnClickListener {
openKeyboard(binding.etInputData)
}
}
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
if (ev.action == MotionEvent.ACTION_DOWN) {
if (!isTouchTargetView(ev, binding.etInputData)) {
// 判断不是触摸输入框的位置则隐藏软键盘
currentFocus?.let { hideKeyboard(it) }
}
}
return super.dispatchTouchEvent(ev)
}
/**
* 判断手指落点是否位于输入框控件区域内。
*/
private fun isTouchTargetView(event: MotionEvent?, view: View?): Boolean {
if (event == null || view == null) return false
val location = IntArray(2)
view.getLocationOnScreen(location)
val left = location[0]
val top = location[1]
val right = left + view.width
val bottom = top + view.height
return event.rawX >= left && event.rawX <= right &&
event.rawY >= top && event.rawY <= bottom
}
/**
* 隐藏软键盘的方法。
*/
private fun hideKeyboard(view: View) {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
/**
* 打开软键盘的方法。
*/
private fun openKeyboard(view: View) {
view.requestFocus()
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
}
}
以上就是几种常见的方式及其实现代码。
评论记录:
回复评论: