Android: 缩放 EditText 的问题以及在父视图之外放置子视图时获取子视图的触摸事件

11
我的问题与Android功能相关,即缩放包含多个子视图的父视图。
ZoomView->ParentView->[多个childViews]
我正在开发一个演示项目来缩放子视图并无限平移。缩放按需完美地工作。 问题1: 但是,如果视图中有EditText,并且我尝试在其上缩放,则会遇到以下问题:
  1. 缩放文本时模糊
  2. 指向文本正常工作,但通过文本进行翻译时,由于其翻译乘以scalingFactor,因此翻译非常快
  3. 选择文本也存在上述问题。
  4. 如果从上面不清楚,请尝试运行演示以了解该问题。

我已尝试两种方法来缩放视图内容,但两种方法都产生了相同的问题。
  • 缩放画布并通过Matrix类的Parent Class缩放MotionEvent来转换MotionEvent。
  • 设置包含childViews的父级的ScaleX和ScaleY
我的演示项目缩放视图的层次结构(UML图)

enter image description here

基本问题是当视图缩放到某个值时,将光标放在正确位置。我已经参考了这个thread问题2:如果我有一个在父视图中可移动的子视图,然后缩小后,如果子视图被平移到父视图的边界外,则事件将无法捕获,并且子视图变得不可触摸。我尝试使用TouchDelegate,但我不知道如何扩展parentView的触摸区域。Codereference Thread

当比例为1时,父视图和ZoomView的触摸区域等于屏幕面积

但是,当比例因子不等于1时,父视图的触摸区域会小于ZoomView,如所显示的那样。 黄色-父视图触摸区域 青色-ZoomView触摸区域 绿色-ChildView触摸区域 截图在此处。

enter image description here

注意: 这是我在StackOverflow上的第一个问题,如果需要进行一些编辑,请推荐。

2个回答

3

这是我解决上述问题最接近的方法。

问题1:

  1. 缩放文本后会出现模糊

setLayerType(LAYER_TYPE_HARDWARE,null);

在文本视图中设置硬件层类型。对于我来说,我将其设置在绿色正方形视图中。

  1. 指向文本时工作正常,但通过文本进行翻译时速度非常快,因为它的翻译乘以了缩放因子
  2. 选择文本也存在上述问题。
对于前两个问题: 这是Android中的一个bug,当你使用scaleX、scaleY API缩放一个视图时,EditText会根据父元素当前的比例值获取事件。但问题出在EditText的光标上。 我们得到的最佳解决方案是编写我们自己的EditTextView(它继承自TextView)。我们查看了Android框架源代码后发现,Android使用PopUpWindow来在屏幕上显示光标。 问题的源头在于当我们使用scaleX和scaleY时,EditText被缩放,因为它的父元素被缩放了,但是光标是一个PopUpWindow而不是EditText的子元素,所以事件没有被缩放,从而出现了上述问题。 因此,我们编写了自己的EditText。如果你查看源代码,你会发现EditText的代码并不是很复杂,可以自己编写。为了解决光标的缩放问题,我们添加了自己的光标PopUpWindow并使其具有缩放感知功能。 注意: (更新) 在这里检查演示代码customEditTextCustomCursor。 运行项目,设置焦点粉色焦点(由Android提供),等待几秒钟,然后黑色的光标将出现,这是自定义光标。 这只是一个非常基本的示例,我们需要自己添加所有其他编辑文本功能,如多选、弹出菜单等。 问题2:如果我有一个可以在父视图中移动的子视图,那么缩小后,如果子视图被移动到父视图范围之外,事件将不再捕获,子视图将变得无法触摸。我尝试使用TouchDelegate,但我不知道如何扩展父视图的触摸区域

这个解决方案是特定于给定问题的而不是通用的,因为可能会有多种解决方案。在这种情况下,有3个视图:

  1. 黄色-绿色正方形视图的父视图
  2. 青色-黄色视图的父视图
  3. 绿色-子视图在父视图外面,不可触摸

    我的解决方案是创建了从绿色正方形视图到黄色父视图的回调。每当绿色正方形视图的平移结束时,回调就会触发,在黄色父视图中,我使用了以下代码。

override fun eventEnded() {
      setDelegate()
    }


fun setDelegate() {
            val rect = Rect()
            val parent = (this.parent as View) 
            parent.getHitRect(rect)
            val touchDelegate = TouchDelegate(rect, this)
            if (View::class.java.isInstance(editorContainer.parent)) {
                (editorContainer.parent as View).touchDelegate = touchDelegate
            }
    }

上面的代码翻译为:当子视图的翻译结束时,检查父级的边界并相应地更新TouchDelegate。我遇到的问题是当我缩放(放大)视图时,视图的委托没有更新,因此解决方案也是从zoomView(parent)到yellowView(childView)进行回调onScaleEnded调用setDelegate()。当比例变化时,hitArea也会发生变化,但根据委托,没有任何变化,因此我们需要更新TouchDelegate的rect。请随意在评论部分讨论。如果有人有更好的解决方案,非常渴望知道。因为我们尝试了许多不同的解决方案,但没有其他方法可行。这是我找到的最好的方法,并且我正在生产中使用上面的代码,到目前为止还没有遇到任何问题。

1
如果您能指导我如何解决EditText中光标缩放的问题,那就太好了。您能分享一个非常简单的示例吗? - Yazon2006
你好,@Yazon2006,我已经更新了答案并在上面的演示项目中添加了代码,请尝试一下。 - Anmol
1
太棒了!做得很好!谢谢你的努力! - Yazon2006

0
最佳的EditText翻译和缩放方法是在此特定EditText上使用scaleX、scaleY、translateX和translateY,而不是在父布局画布翻译中进行。例如,在kotlin中:
editText.scaleX = scaleFactor
editText.scaleY = scaleFactor
editText.translateX = offsetLeft
editText.translateн = offsetTop

顺便提一下,在Android Studio中可以使用工具->布局检查器来检查触摸区域和绘图区域是否相同。


针对我的使用情况,我想要缩放整个父级视图而不是特定的编辑框,并且一旦你缩放了父级视图,它的所有子视图都会被缩放。 - Anmol
@Anmol,将比例尺传递给每个子视图很容易。相信我,这个翻译EditText控件的问题并不是唯一的问题。这个可触摸区域也可能被Android识别为屏幕外的视图,无法正确渲染。只需将测试放在布局的右侧,并尝试在Android 5.1上进行编辑。您会发现它根本没有呈现,直到您调用requestFocus或invalidate。用户将无法实时看到文本更改。 - Yazon2006
你能分享一些代码和示例,说明你是如何解决缩放问题的吗?我无法理解,请在回答中更新。 - Anmol
很抱歉,@Anmol,我不能分享项目代码的任何部分 :( - Yazon2006

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接