有没有办法以编程方式将滚动视图滚动到特定的编辑文本?

Not*_*Man 187 android view scrollview android-edittext programmatically-created

我有一个很长的活动与scrollview.这是一个包含用户必须填写的各种字段的表单.我的表单中有一个复选框,当用户检查它时,我想滚动到视图的特定部分.有没有办法以编程方式滚动到EditText对象(或任何其他视图对象)?

此外,我知道这可能使用X和Y坐标,但我想避免这样做,因为表单可能会从用户更改为用户.

She*_*tib 425

private final void focusOnView(){
        your_scrollview.post(new Runnable() {
            @Override
            public void run() {
                your_scrollview.scrollTo(0, your_EditBox.getBottom());
            }
        });
    }
Run Code Online (Sandbox Code Playgroud)

  • 我发现使用smoothScrollTo(0,your_EditBox.getTop())获得了更好的结果(扼杀滚动到所需的视图)但除此之外 - 很好的答案. (120认同)
  • 也可以将Runnable发布到ScrollView本身,而不是实例化一个新的Handler:`your_scrollview.post(...` (35认同)
  • @ xmenW.K.简答:因为UI基于要做的事情的队列来完成其工作,并且你基本上是在告诉UI线程,在你完成所有你以前必须做的事之后,你可以做到这一点(滚动) .你基本上把滚动放在队列中,让线程尽可能地执行它,在你请求它之前尊重它正在做的事情的顺序. (18认同)
  • getBottom()和getTop()是相对于父级的 (3认同)
  • 为什么是“getBottom()”,而不是“getTop()”? (2认同)

ahm*_*och 53

如果要将视图滚动滚动视图的中心,可以大大改善Sherif elKhatib的答案.这种可重用的方法可以平滑地将视图滚动到Horizo​​ntalScrollView的可见中心.

private final void focusOnView(final HorizontalScrollView scroll, final View view) {
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            int vLeft = view.getLeft();
            int vRight = view.getRight();
            int sWidth = scroll.getWidth();
            scroll.smoothScrollTo(((vLeft + vRight - sWidth) / 2), 0);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

用于垂直ScrollView改变输入xy输入的位置smoothScroll.并使用view.getTop(),而不是view.getLeft()view.getBottom()代替v.getRight().

:)

  • 你必须调整你的代码.您必须获得滚动视图的宽度,您必须将公式更改为sv.smoothScrollTo(((vLeft + vRight)/ 2) - (svWidth/2),0); (3认同)
  • 否则,scrollView中的视图将不会居中.我已经为你做了编辑. (2认同)

Swa*_*_99 48

这适合我:

  targetView.getParent().requestChildFocus(targetView,targetView);
Run Code Online (Sandbox Code Playgroud)

public void RequestChildFocus(查看子项,查看焦点)

child - 此ViewParent的子项需要焦点.该视图将包含焦点视图.实际上并不一定是关注焦点的观点.

专注 -这是孩子的后代,实际上有焦点的视图


Mic*_*ael 27

在我看来,滚动到给定矩形的最佳方法是通过View.requestRectangleOnScreen(Rect, Boolean).您应该在View想要滚动到并传递要在屏幕上显示的本地矩形的情况下调用它.第二个参数应该是false平滑滚动和true立即滚动.

final Rect rect = new Rect(0, 0, view.getWidth(), view.getHeight());
view.requestRectangleOnScreen(rect, false);
Run Code Online (Sandbox Code Playgroud)

  • 绝对这应该是公认的答案,如果所需的视图不在屏幕上,`scrollview.smoothScrollTo` 将不起作用(在 sdk 版本 26 的 android 模拟器中尝试) (3认同)

Tob*_*run 12

我根据WarrenFaith的答案制作了一个小实用工具方法,如果该视图在滚动视图中已经可见,则该代码也会考虑,不需要滚动.

public static void scrollToView(final ScrollView scrollView, final View view) {

    // View needs a focus
    view.requestFocus();

    // Determine if scroll needs to happen
    final Rect scrollBounds = new Rect();
    scrollView.getHitRect(scrollBounds);
    if (!view.getLocalVisibleRect(scrollBounds)) {
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                scrollView.smoothScrollTo(0, view.getBottom());
            }
        });
    } 
}
Run Code Online (Sandbox Code Playgroud)


Ovi*_*tcu 10

您应该TextView重点关注您的请求:

    mTextView.requestFocus();
Run Code Online (Sandbox Code Playgroud)


小智 6

我的EditText嵌套在我的ScrollView中的几个层,它本身不是布局的根视图.因为getTop()和getBottom()似乎报告了它包含视图的坐标,所以我通过遍历EditText的父节点来计算从ScrollView顶部到EditText顶部的距离.

// Scroll the view so that the touched editText is near the top of the scroll view
new Thread(new Runnable()
{
    @Override
    public
    void run ()
    {
        // Make it feel like a two step process
        Utils.sleep(333);

        // Determine where to set the scroll-to to by measuring the distance from the top of the scroll view
        // to the control to focus on by summing the "top" position of each view in the hierarchy.
        int yDistanceToControlsView = 0;
        View parentView = (View) m_editTextControl.getParent();
        while (true)
        {
            if (parentView.equals(scrollView))
            {
                break;
            }
            yDistanceToControlsView += parentView.getTop();
            parentView = (View) parentView.getParent();
        }

        // Compute the final position value for the top and bottom of the control in the scroll view.
        final int topInScrollView = yDistanceToControlsView + m_editTextControl.getTop();
        final int bottomInScrollView = yDistanceToControlsView + m_editTextControl.getBottom();

        // Post the scroll action to happen on the scrollView with the UI thread.
        scrollView.post(new Runnable()
        {
            @Override
            public void run()
            {
                int height =m_editTextControl.getHeight();
                scrollView.smoothScrollTo(0, ((topInScrollView + bottomInScrollView) / 2) - height);
                m_editTextControl.requestFocus();
            }
        });
    }
}).start();
Run Code Online (Sandbox Code Playgroud)


Gor*_*ail 5

另一种变体是:

scrollView.postDelayed(new Runnable()
{
    @Override
    public void run()
    {
        scrollView.smoothScrollTo(0, img_transparent.getTop());
    }
}, 2000);
Run Code Online (Sandbox Code Playgroud)

或者您可以使用该post()方法。


小智 5

如果 ScrollView 是 ChildView 的直接父级,则上述答案将正常工作。如果您的 ChildView 被包装在 ScrollView 中的另一个 ViewGroup 中,则会导致意外行为,因为 View.getTop() 获取相对于其父级的位置。在这种情况下,您需要实现:

public static void scrollToInvalidInputView(ScrollView scrollView, View view) {
    int vTop = view.getTop();

    while (!(view.getParent() instanceof ScrollView)) {
        view = (View) view.getParent();
        vTop += view.getTop();
    }

    final int scrollPosition = vTop;

    new Handler().post(() -> scrollView.smoothScrollTo(0, scrollPosition));
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我知道这对于更好的答案可能为时已晚,但理想的完美解决方案必须是像定位器这样的系统。我的意思是,当系统为编辑器字段定位时,它会将字段放置在键盘上,因此作为 UI/UX 规则,它是完美的。

下面的代码使得Android方式定位顺利。首先,我们将当前滚动点作为参考点。第二件事是为编辑器找到最佳定位滚动点,为此我们滚动到顶部,然后请求编辑器字段使 ScrollView 组件进行最佳定位。嘎查!我们已经学会了最好的位置。现在,我们要做的是从上一个点平滑滚动到我们新发现的点。如果需要,您可以仅使用scrollTo而不是smoothScrollTo来省略平滑滚动。

注意:主容器 ScrollView 是一个名为 scrollViewSignup 的成员字段,因为我的示例是一个注册屏幕,您可能会发现很多。

view.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(final View view, boolean b) {
            if (b) {
                scrollViewSignup.post(new Runnable() {
                    @Override
                    public void run() {
                        int scrollY = scrollViewSignup.getScrollY();
                        scrollViewSignup.scrollTo(0, 0);
                        final Rect rect = new Rect(0, 0, view.getWidth(), view.getHeight());
                        view.requestRectangleOnScreen(rect, true);

                        int new_scrollY = scrollViewSignup.getScrollY();
                        scrollViewSignup.scrollTo(0, scrollY);
                        scrollViewSignup.smoothScrollTo(0, new_scrollY);
                    }
                });
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

如果您想将此块用于所有EditText实例,并快速将其与您的屏幕代码集成。您可以简单地制作一个如下所示的遍历器。为此,我将主 OnFocusChangeListener 设为名为focusChangeListenerToScrollEditor的成员字段,并在 onCreate 期间调用它,如下所示。

traverseEditTextChildren(scrollViewSignup, focusChangeListenerToScrollEditor);
Run Code Online (Sandbox Code Playgroud)

方法实现如下。

private void traverseEditTextChildren(ViewGroup viewGroup, View.OnFocusChangeListener focusChangeListenerToScrollEditor) {
    int childCount = viewGroup.getChildCount();
    for (int i = 0; i < childCount; i++) {
        View view = viewGroup.getChildAt(i);
        if (view instanceof EditText)
        {
            ((EditText) view).setOnFocusChangeListener(focusChangeListenerToScrollEditor);
        }
        else if (view instanceof ViewGroup)
        {
            traverseEditTextChildren((ViewGroup) view, focusChangeListenerToScrollEditor);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,我们在这里所做的是让所有 EditText 实例子级调用焦点上的侦听器。

为了达到这个解决方案,我已经检查了这里的所有解决方案,并生成了一个新的解决方案以获得更好的 UI/UX 结果。

非常感谢所有其他给我很大启发的答案。