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

此外,我知道这是可能的使用X和Y坐标,但我想避免这样做,因为形式可能会从用户到用户的变化。


当前回答

我知道这可能太迟了,没有更好的答案,但理想的完美解决方案必须是一个像定位器这样的系统。我的意思是,当系统为一个编辑器字段进行定位时,它将该字段放置在键盘上方,因此作为UI/UX规则,这是完美的。

What below code makes is the Android way positioning smoothly. First of all we keep the current scroll point as a reference point. Second thing is to find the best positioning scroll point for an editor, to do this we scroll to top, and then request the editor fields to make the ScrollView component to do the best positioning. Gatcha! We've learned the best position. Now, what we'll do is scroll smoothly from the previous point to the point we've found newly. If you want you may omit smooth scrolling by using scrollTo instead of smoothScrollTo only.

注意:主容器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);
                    }
                });
            }
        }
    });

如果您希望将此块用于所有EditText实例,并将其与屏幕代码快速集成。您可以简单地像下面这样创建一个遍历器。为此,我已经使主OnFocusChangeListener一个名为focusChangeListenerToScrollEditor的成员字段,并在onCreate期间调用它如下所示。

traverseEditTextChildren(scrollViewSignup, focusChangeListenerToScrollEditor);

方法实现如下所示。

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);
        }
    }
}

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

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

Many thanks to all other answers inspiring me much.

其他回答

参考资料:https://stackoverflow.com/a/6438240/2624806

接下来的工作要好得多。

mObservableScrollView.post(new Runnable() {
            public void run() { 
                mObservableScrollView.fullScroll([View_FOCUS][1]); 
            }
        });

我知道这可能太迟了,没有更好的答案,但理想的完美解决方案必须是一个像定位器这样的系统。我的意思是,当系统为一个编辑器字段进行定位时,它将该字段放置在键盘上方,因此作为UI/UX规则,这是完美的。

What below code makes is the Android way positioning smoothly. First of all we keep the current scroll point as a reference point. Second thing is to find the best positioning scroll point for an editor, to do this we scroll to top, and then request the editor fields to make the ScrollView component to do the best positioning. Gatcha! We've learned the best position. Now, what we'll do is scroll smoothly from the previous point to the point we've found newly. If you want you may omit smooth scrolling by using scrollTo instead of smoothScrollTo only.

注意:主容器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);
                    }
                });
            }
        }
    });

如果您希望将此块用于所有EditText实例,并将其与屏幕代码快速集成。您可以简单地像下面这样创建一个遍历器。为此,我已经使主OnFocusChangeListener一个名为focusChangeListenerToScrollEditor的成员字段,并在onCreate期间调用它如下所示。

traverseEditTextChildren(scrollViewSignup, focusChangeListenerToScrollEditor);

方法实现如下所示。

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);
        }
    }
}

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

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

Many thanks to all other answers inspiring me much.

以下是我正在使用的:

int amountToScroll = viewToShow.getBottom() - scrollView.getHeight() + ((LinearLayout.LayoutParams) viewToShow.getLayoutParams()).bottomMargin;
// Check to see if scrolling is necessary to show the view
if (amountToScroll > 0){
    scrollView.smoothScrollTo(0, amountToScroll);
}

这将获得显示视图底部所需的滚动量,包括视图底部的任何边距。

我的解决方案是:

            int[] spinnerLocation = {0,0};
            spinner.getLocationOnScreen(spinnerLocation);

            int[] scrollLocation = {0, 0};
            scrollView.getLocationInWindow(scrollLocation);

            int y = scrollView.getScrollY();

            scrollView.smoothScrollTo(0, y + spinnerLocation[1] - scrollLocation[1]);

另一种说法是:

scrollView.postDelayed(new Runnable()
{
    @Override
    public void run()
    {
        scrollView.smoothScrollTo(0, img_transparent.getTop());
    }
}, 200);

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