首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >当具有可选文本的ScrollView成为焦点时,停止TextView滚动

当具有可选文本的ScrollView成为焦点时,停止TextView滚动
EN

Stack Overflow用户
提问于 2020-11-28 22:57:59
回答 1查看 402关注 0票数 3

我有一个ScrollView,它的布局中嵌套了多个TextView子级。我希望这些子程序中的文本是可选择的(android:textIsSelectable="true"),这样用户就可以使用复制、共享和选择所有操作。但是,当其中一个孩子收到焦点(来自触摸或长按压)时,它会导致父ScrollView滚动到聚焦子。我想这是一个特性,但它给我带来了三个问题。

当使用长按压选择文本时,它会导致文本滚动,因此,聚焦子文件上方的子程序将滚动到可见边界之外。unintuitive.

  • My
  1. 所选文本的位置将发生变化,不会出现在用户进行长按压的屏幕上,即应用程序响应双击手势。双击的第一个触摸(或点击)将导致接收触摸事件的子节点接收焦点,从而导致滚动。显然,滚动将导致手势失败;子动作被触摸,父滚动,子项再次被触摸,但未检测到双击手势。。

使子程序不可聚焦会阻止滚动,但不能选择文本。那么,如何将TextView视图嵌套在一个具有可选文本的ScrollView中,但当其中一个视图收到焦点时却防止滚动?

EN

回答 1

Stack Overflow用户

发布于 2020-11-28 22:57:59

在寻找这个问题的可能解决方案时,我发现了本文https://programmersought.com/article/8487993014/。它与这个问题没有直接关系,但是本文展示了ScrollView的一些源代码的一个特定部分引起了我的注意:

代码语言:javascript
运行
复制
    public void requestChildFocus(View child, View focused) {
        if (focused != null && focused.getRevealOnFocusHint()) {
                         If (!mIsLayoutDirty) {//This boolean value marks whether the layout has been completed. If it is completed, it is false.
                scrollToChild(focused);
            } else {
                // The child may not be laid out yet, we can't compute the scroll yet
                mChildToScrollTo = focused;
            }
        }
 //super method [handling FOCUS_BLOCK_DESCENDANTS case] is called after scrolling on top.
 //So setting the android:descendantFocusability="blocksDescendants" attribute to the ScrollView is invalid.
        super.requestChildFocus(child, focused);
    }

在这里,您可以看到ScrollView将尝试滚动到聚焦子focused != null。因此,若要禁用此行为,请创建ScrollView的子类并覆盖此方法,如下所示:

代码语言:javascript
运行
复制
package com.test

// imports here...

public class MyScrollView extends ScrollView {

    // constructors here...

    @Override
    public void requestChildFocus(View child, View focused) {
        super.requestChildFocus(child, null);
    }
}

通过忽略focused参数并将null传递给超级实现,滚动将永远不会发生,但父文件仍将请求子节点接收焦点,因此仍然可以选择文本。

唯一要做的事情是用上面定义的自定义实现替换布局文件中的ScrollView父文件。

编辑解决方案在API 30上测试并运行良好,但当我在API 25上测试它时,会抛出NPE并导致应用程序崩溃。Android建议使用NestedScrollView视图进行垂直滚动,但应用程序仍然崩溃。我查看了requestChildFocus(View, View)的源代码,它略有不同:

代码语言:javascript
运行
复制
@Override
public void requestChildFocus(View child, View focused) {
    if (!mIsLayoutDirty) {
        scrollToChild(focused);
    } else {
        // The child may not be laid out yet, we can't compute the scroll yet
        mChildToScrollTo = focused;
    }
    super.requestChildFocus(child, focused);
}

private void scrollToChild(View child) {
    child.getDrawingRect(mTempRect);

    /* Offset from child's local coordinates to ScrollView coordinates */
        offsetDescendantRectToMyCoords(child, mTempRect);

    int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);

    if (scrollDelta != 0) {
        scrollBy(0, scrollDelta);
    }
}

方法scrollToChild(View)是私有的,因此我们不能覆盖默认实现(因为为什么会有人想要这样做,对吗?),但是scrollBy(int, int)是公共的。因此,与其在MyScrollView类中重写MyScrollView,不如重写scrollBy(int, int),让它什么也不做。这在API 30和25上都进行了测试,并且在不崩溃的情况下正常工作。后来,我试图恢复到扩展ScrollView,但它仍然有效。所以你只需要重写这个方法,超级类型就不重要了。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65055293

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档