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

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


当前回答

垂直滚动,适合窗体。答案是基于艾哈迈迪巴洛赫水平卷轴。

private final void focusOnView(final HorizontalScrollView scroll, final View view) {
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            int top = view.getTop();
            int bottom = view.getBottom();
            int sHeight = scroll.getHeight();
            scroll.smoothScrollTo(0, ((top + bottom - sHeight) / 2));
        }
    });
}

其他回答

这对我来说很管用:

  targetView.getParent().requestChildFocus(targetView,targetView);

RequestChildFocus(查看子视图,查看焦点)

child -这个ViewParent的想要聚焦的子对象。该视图将包含聚焦视图。它并不一定是真正有焦点的观点。

focused -实际上具有焦点的child的后代视图

Sherif elKhatib的答案可以大大改进,如果你想将视图滚动到滚动视图的中心。这个可重用的方法平滑地将视图滚动到HorizontalScrollView的可见中心。

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

对于垂直ScrollView的使用

...
int vTop = view.getTop();
int vBottom = view.getBottom();
int sHeight = scroll.getBottom();
scroll.smoothScrollTo(0, ((vTop + vBottom - sHeight) / 2));
...

问:有没有一种方法,以编程方式滚动滚动视图到特定的编辑文本?

答:嵌套滚动视图在recyclerview最后位置添加记录数据。

adapter.notifyDataSetChanged();
nested_scroll.setScrollY(more Detail Recycler.getBottom());

是否有一种方法以编程方式滚动滚动视图到特定的编辑文本?

如果你想在打开软键盘时滚动到一个视图,那么这可能有点棘手。 到目前为止,我得到的最好的解决方案是使用嵌套回调和requestRectangleOnScreen方法的组合。

首先,你需要设置inset回调:

fun View.doOnApplyWindowInsetsInRoot(block: (View, WindowInsetsCompat, Rect) -> Unit) {
    val initialPadding = recordInitialPaddingForView(this)
    val root = getRootForView(this)
    ViewCompat.setOnApplyWindowInsetsListener(root) { v, insets ->
        block(v, insets, initialPadding)
        insets
    }
    requestApplyInsetsWhenAttached()
}

fun View.requestApplyInsetsWhenAttached() {
    if (isAttachedToWindow) {
        requestApplyInsets()
    } else {
        addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
            override fun onViewAttachedToWindow(v: View) {
                v.removeOnAttachStateChangeListener(this)
                v.requestApplyInsets()
            }

            override fun onViewDetachedFromWindow(v: View) = Unit
        })
    }
}

我们在根视图上设置了一个回调来确保我们被调用。插图可能在我们的视图接收到它们之前就被消耗掉了,所以我们必须在这里做额外的工作。

现在很简单了:

doOnApplyWindowInsetsInRoot { _, _, _ ->
    post {
        if (viewInQuestion.hasFocus()) {
            requestRectangleOnScreen(Rect(0, 0, width, height))
        }
    }
}

你可以摆脱焦点检查。它的存在是为了限制requestRectangleOnScreen的调用数量。我使用post在可滚动的父滚动到聚焦视图后运行一个操作。

如果sclmain是你的NestedScrollView,那么使用以下方法:

scrlMain.post(new Runnable() {
    @Override
    public void run() {
        scrlMain.fullScroll(View.FOCUS_UP);
    }
});