EditText与NestScrollView嵌套使用时,滑动冲突处理

devtools/2024/9/23 10:24:53/

期望

Android开发中经常会有在一个大页面中,包含一个EditText的情况,一般情况下,大页面会通过NestScrollView或者ScrollView当作根View

于是在布局文件中,我们常常这么写:

<?xml version="1.0" encoding="utf-8"?>  
<androidx.core.widget.NestedScrollView  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=".EditTextScrollActivity">  <LinearLayout  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:orientation="vertical" > 	 <View  android:layout_width="match_parent"  android:layout_height="400dp"  android:background="@android:color/holo_blue_bright"  />  <EditText  android:id="@+id/et"  android:layout_width="match_parent"  android:layout_height="100dp"/>  <View  android:layout_width="match_parent"  android:layout_height="600dp"  android:background="@android:color/holo_red_light"  />  </LinearLayout>  </androidx.core.widget.NestedScrollView>

EditText上下的两个View是为了模拟其他内容,以达到让整个页面显示超过屏幕高度的效果。

在这种情况下,我们根据UI稿设置了一个固定高度的EditText,这时直接运行时会发现一个问题,我们输入了过高的文字时,EditText内的文字无法正常上下划动了。

此时我们提出我们的期望:

  1. EditText内的内容,超出自身的高度时:
    1. 手指上划时,若EditText还没划到底,则划动EditText的内容部分;当Edit Text划到底时,整体页面上划。
    2. 手指下划时,若EditText还没划到顶,则划动EditText的内容部分;当Edit Text划到顶时,整体页面下划。
  2. EditText内的内容没有超出自身高度时:
    1. 划动整体页面

实现方案

这是典型的划动冲突问题,解决方案就从事件分发入手了。

如果想要了解事件分发,请查阅我之前发表的博客。

事件分发汇总帖

总之,我们此刻一句话描述我们的处理逻辑:

  1. EditText内部内容能够划动,划内部,若EditText内部内容不能划动,划外部。
  2. 如何控制划内部外部?使用requestDisallowInterceptTouchEvent

接下来写一下代码吧!

public class EditTextTouchListener(view: EditText) : OnTouchListener {  private var viewConfig = ViewConfiguration.get(view.context)  private var originalTouchY: Float = 0f  private var originalTouchX: Float = 0f  @SuppressLint("ClickableViewAccessibility")  override fun onTouch(v: View?, event: MotionEvent?): Boolean {  event ?: return false  if (v is EditText) {  when (event.actionMasked) {  MotionEvent.ACTION_DOWN -> {  // 1 按下时,记录一下位置,并请求父布局不要拦截事件v.parent?.requestDisallowInterceptTouchEvent(true)  originalTouchY = event.y  originalTouchX = event.x  }  MotionEvent.ACTION_MOVE -> {  val nowY = event.y  val nowX = event.x  // 计算X方向划动距离val distance = abs(nowX - originalTouchX)  // 如果横向划动已经超过了最小值,交由EditText自己处理if (viewConfig.scaledTouchSlop < distance ) {  return false  }  // 计算竖直方向,如果划动距离小于最小值,交给EditText自己处理if (abs(nowY - originalTouchY) < viewConfig.scaledTouchSlop) {  return false  }  // 执行到此处,那么竖直方向一定划动超过了最小值,此时判断是,向上划动还是向下划动。// 如果当前位置Y大于  初始Y,即手指下划if (nowY > originalTouchY) {  return if (v.canScrollVertically(-1)) {  false  }else {  v.parent?.requestDisallowInterceptTouchEvent(false)  true  }  }else {  // 如果当前位置Y小于 初始Y,即手指上划if (nowY < originalTouchY) {  return if (v.canScrollVertically(1)) {  false  }else {  v.parent?.requestDisallowInterceptTouchEvent(false)  true  }  }  }  }  else -> {  v.parent?.requestDisallowInterceptTouchEvent(false)  }  }  }  return false  }  }

这种实现方案有一个问题:

当划动交给外部之后,便一直由外部处理了:

假设,EditText的内容可以往上划动,那我开始划动,划动到底之后,EditText不能继续往上划了之后,把滑动操作交给了外边的NestScrollView;此时,手不松开,开始反向滑动,EditText也不会滑动里边的内容了。

当然这种已经已经满足我的期望了。

延申

上面的实现方案满足了产品需求、UI需求,但是我在想,还可以实现另一种,就是当手指划出EditView的范围之后,就不再可划。


public class EditTextRangeTouchListener(view: EditText) : OnTouchListener {  private var viewConfig = ViewConfiguration.get(view.context)  private var originalTouchY: Float = 0f  private var originalTouchX: Float = 0f  @SuppressLint("ClickableViewAccessibility")  override fun onTouch(v: View?, event: MotionEvent?): Boolean {  event ?: return false  if (v is EditText) {  when (event.actionMasked) {  MotionEvent.ACTION_DOWN -> {  v.parent?.requestDisallowInterceptTouchEvent(true)  originalTouchY = event.y  originalTouchX = event.x  }  MotionEvent.ACTION_MOVE -> {  val nowY = event.y  val nowX = event.x  val distance = abs(nowX - originalTouchX)  if (nowY < 0 || nowY > v.height) {  v.parent?.requestDisallowInterceptTouchEvent(false)  return true  }  if (viewConfig.scaledTouchSlop < distance ) {  return false  }  if (abs(nowY - originalTouchY) < viewConfig.scaledTouchSlop) {  return false  }  if (nowY > originalTouchY) {  return if (v.canScrollVertically(-1)) {  false  }else {  v.parent?.requestDisallowInterceptTouchEvent(false)  true  }  }else {  if (nowY < originalTouchY) {  return if (v.canScrollVertically(1)) {  false  }else {  v.parent?.requestDisallowInterceptTouchEvent(false)  true  }  }  }  }  else -> {  v.parent?.requestDisallowInterceptTouchEvent(false)  }  }  }  return false  }  }

这种实现方式放到NestScrollView中,划起来还是挺怪的。这个方案不采用了。


http://www.ppmy.cn/devtools/28805.html

相关文章

RAG-Driver: 多模态大语言模型中具有检索增强上下文学习的通用驱动解释

RAG-Driver: 多模态大语言模型中具有检索增强上下文学习的通用驱动解释 摘要Introduction RAG-Driver: Generalisable Driving Explanations with Retrieval-Augmented In-Context Learning in Multi-Modal Large Language Model. 摘要 由“黑箱”模型驱动的机器人需要提供人类…

AI大模型探索之路-训练篇7:大语言模型Transformer库之HuggingFace介绍

系列篇章&#x1f4a5; AI大模型探索之路-训练篇1&#xff1a;大语言模型微调基础认知 AI大模型探索之路-训练篇2&#xff1a;大语言模型预训练基础认知 AI大模型探索之路-训练篇3&#xff1a;大语言模型全景解读 AI大模型探索之路-训练篇4&#xff1a;大语言模型训练数据集概…

huggingface里如何查看具体任务的评估指标

如果我们在做一个模型训练任务的时候&#xff0c;可能会不知道这个任务在评估的时候使用什么指标&#xff0c;那么huggingface里边为我们提供了参考&#xff1a; 下面就来看看吧&#xff1a; https://huggingface.co/https://huggingface.co/ 点击"Docs"&#xff…

微星主板安装双系统不能进入Ubuntu的解决办法

在微星主板的台式机上面依次安装了Windows11和Ubuntu22.04。在Ubuntu安装完成后重启&#xff0c;没有出现系统选择界面&#xff0c;直接进入了Windows11。怎么解决&#xff1f;方法如下&#xff1a; &#xff08;1&#xff09;正常安装Windows11 &#xff08;2&#xff09;安…

B树、B+树、B*树

平衡二叉树、B树、B树、B*树 理解其中一种你就都明白了 - 知乎 补补数据结构&#xff0c;讲得很好的文章。 https://www.cnblogs.com/nanlinghan/p/10315653.html B树 二叉树 B-Tree BTree 详解_b树英文-CSDN博客 B-树&#xff08;B树&#xff09;详解 - 简书 图解B树的原…

大数据分析入门之10分钟掌握order by排序

前言 书接上回大数据分析入门10分钟快速了解SQL 本篇将会进一步介绍order by排序。 基本语法 SELECT column1, column2, ... FROM table_name ORDER BY column1, column2, ... ASC|DESC -- 可以按多列排序 LIMIT n; -- 截取排序后的前n项假设我们有students表&#xff0c;其…

SpringBoot camunda

1&#xff1a;默认排他网关&#xff0c;表达式 Type:expression:${number%2000} 2: service task (系统自动执行用的最多):常用Delegate expression ${testGateWay} 举例&#xff1a; Component("testGateWay") public class TestGateWay implements JavaDelegate {…

css如何去掉重叠部分的边框,CSS中nth-child不生效

css如何去掉重叠部分的边框 div使用负的margin&#xff0c;margin-right:-1px&#xff1b;table表格设置边框后的重叠&#xff0c;border-collapse: collapse CSS中nth-child不生效 <body><ul><li><a><span class"item"></span&…