如何解决如何正确支持点击 Android 中的可选文本视图
<LinearLayout
android:id="@+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/rectangular_background">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="true"
android:text="Clickable"/>
</LinearLayout>
为 LinearLayout 分配一个点击监听器
linear_layout.setonClickListener {
Toast.makeText(context,"Linear Layout clicked",Toast.LENGTH_SHORT).show()
}
当 Toast 具有可选文本时,单击文本视图时不会显示 Toast。我在 this 答案中尝试了一个解决方案,方法是在通用函数中添加以下代码以用于所有文本视图。
val textGestureDetector = GestureDetectorCompat(context,GestureDetector.SimpleOnGestureListener())
textGestureDetector.setonDoubleTapListener(object : GestureDetector.OnDoubleTapListener {
override fun onDoubleTap(e: MotionEvent?): Boolean = false
override fun onDoubleTapEvent(e: MotionEvent?): Boolean = false
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
textView.performClick()
return true
}
})
textView.setonTouchListener { _,event ->
textGestureDetector.onTouchEvent(event)
false
}
当我们在文本视图上分配单击侦听器时,此解决方案确实有效,但是当文本视图没有单击侦听器时,单击事件不会传播到线性布局。
由于线性布局中可以有多个子文本视图,所以我不想显式编写代码来在每个子级单击时调用父级的单击侦听器。有没有办法用通用的解决方案来解决这个问题?
编辑: 理想情况下,我想创建一个自定义文本视图,无论文本是否可选,它都能正确传播点击。这将有助于在我的整个应用程序中解决这个问题。 正确传播点击意味着三件事:
解决方法
据我所知,您想将可选文本视图的点击传递给其父视图。
要执行此操作,请单击子视图(可选文本视图)的 onSingleTapConfirmed
中的父级。
val textGestureDetector = GestureDetectorCompat(this,GestureDetector.SimpleOnGestureListener())
textGestureDetector.setOnDoubleTapListener(object : GestureDetector.OnDoubleTapListener {
override fun onDoubleTap(e: MotionEvent?): Boolean = false
override fun onDoubleTapEvent(e: MotionEvent?): Boolean = false
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
// pass the click event to its parent
(textView.parent as? View)?.performClick()
return true
}
})
textView.setOnTouchListener { _,event ->
textGestureDetector.onTouchEvent(event)
false
}
linearLayout.setOnClickListener {
Toast.makeText(context,Toast.LENGTH_LONG,Toast.LENGTH_LONG).show()
}
,
简介
从您的问题看来,您要实现的目标如下:
- 如果您的
split_list <- split(someVector,gsub(pattern = "\\s.*","",someVector)) music <- split_list$music painting <- split_list$painting sports <- split_list$sports
是 textSelectable,那么单击它应该委托给TextView
。 - 长按或双击仍应由
linear_layout
处理
可能的解决方案
为什么不递归地将自定义 TextView
设置为每个后代 textGestureDetector
?在这种情况下,您无需为每个孩子/后代 TextView
手动执行此操作。
因此,首先,将您在 TextView
中的活动委托给 onSingleTapConfirmed
,如下所示:
linear_layout
然后,将您的 val textGestureDetector = GestureDetectorCompat(context,GestureDetector.SimpleOnGestureListener())
textGestureDetector.setOnDoubleTapListener(object : GestureDetector.OnDoubleTapListener {
override fun onDoubleTap(e: MotionEvent?): Boolean = false
override fun onDoubleTapEvent(e: MotionEvent?): Boolean = false
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
// pass the click event to your linear_layout
linearLayout.performClick()
return true
}
})
添加到 OnClickListener
中,如下所示:
linear_layout
最后,调用 linear_layout.setOnClickListener {
Toast.makeText(context,"click just happened",Toast.LENGTH_LONG).show()
}
(这会将您的自定义 initTextViewSingleTapListener
设置为每个 onTapListener
的后代 TextView
)
linear_layout
它可以实现如下:
initTextViewSingleTapListener(linear_layout,linear_layout,textGestureDetector)
如果您的 fun initTextViewSingleTapListener(root: ViewGroup,currentView: View,textGestureDetector: GestureDetectorCompat) {
if (currentView is TextView) {
currentView.setOnTouchListener { _,event ->
textGestureDetector.onTouchEvent(event)
false
}
return
}
if (currentView is ViewGroup) {
for (i in 0..currentView.childCount) {
val child = currentView.getChildAt(i)
if (child != null) {
initTextViewSingleTapListener(root,child,textGestureDetector)
}
}
}
}
已经有一个监听器,所以您不想替换它,那么只需在添加您的监听器之前添加一个像 TextView
这样的检查:
!currentView.hasOnClickListeners()
完整代码
请在下面找到完整的示例代码:
...
if (!currentView.hasOnClickListeners()) {
currentView.setOnTouchListener { _,event ->
textGestureDetector.onTouchEvent(event)
false
}
}
...
更新
由于您的问题要求发生了变化,我在此处添加了额外的解释。
如果一个 textSelectable override fun onViewCreated(view: View,savedInstanceState: Bundle?) {
super.onViewCreated(view,savedInstanceState)
val textGestureDetector = GestureDetectorCompat(context,GestureDetector.SimpleOnGestureListener())
textGestureDetector.setOnDoubleTapListener(object : GestureDetector.OnDoubleTapListener {
override fun onDoubleTap(e: MotionEvent?): Boolean = false
override fun onDoubleTapEvent(e: MotionEvent?): Boolean = false
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
// pass the click event to the linear layout
linear_layout.performClick()
return true
}
})
linear_layout.setOnClickListener {
Toast.makeText(context,Toast.LENGTH_LONG).show()
}
initTextViewSingleTapListener(linear_layout,textGestureDetector)
}
fun initTextViewSingleTapListener(root: ViewGroup,textGestureDetector: GestureDetectorCompat) {
if (currentView is TextView) {
if (currentView.hasOnClickListeners()) {
// do nothing since your View already has a click listener on it.
return
}
currentView.setOnTouchListener { _,textGestureDetector)
}
}
}
}
应该将一个点击事件委托给它最近的 TextView
祖先,那么在您的 ViewGroup
块中,如下所示:
initTextViewSingleTapListener()'s
将 if (currentView is ViewGroup) {
for (i in 0..currentView.childCount) {
val child = currentView.getChildAt(i)
if (child != null) {
initTextViewSingleTapListener(root,textGestureDetector)
}
}
}
替换为 root
,以便将所有单击事件委托给最近的 currentView
祖先:
ViewGroup
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。