我有一个很长的带有滚动视图的活动。它是一个包含用户必须填写的各种字段的表单。我在表单的中间有一个复选框,当用户选中它时,我想滚动到视图的特定部分。是否有办法以编程方式滚动到EditText对象(或任何其他视图对象)?
此外,我知道这是可能的使用X和Y坐标,但我想避免这样做,因为形式可能会从用户到用户的变化。
我有一个很长的带有滚动视图的活动。它是一个包含用户必须填写的各种字段的表单。我在表单的中间有一个复选框,当用户选中它时,我想滚动到视图的特定部分。是否有办法以编程方式滚动到EditText对象(或任何其他视图对象)?
此外,我知道这是可能的使用X和Y坐标,但我想避免这样做,因为形式可能会从用户到用户的变化。
当前回答
另一种说法是:
scrollView.postDelayed(new Runnable()
{
@Override
public void run()
{
scrollView.smoothScrollTo(0, img_transparent.getTop());
}
}, 200);
或者可以使用post()方法。
其他回答
如果你想在打开软键盘时滚动到一个视图,那么这可能有点棘手。 到目前为止,我得到的最好的解决方案是使用嵌套回调和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在可滚动的父滚动到聚焦视图后运行一个操作。
我的解决方案是:
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]);
以下是我正在使用的:
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);
}
这将获得显示视图底部所需的滚动量,包括视图底部的任何边距。
这对我来说很管用:
targetView.getParent().requestChildFocus(targetView,targetView);
RequestChildFocus(查看子视图,查看焦点)
child -这个ViewParent的想要聚焦的子对象。该视图将包含聚焦视图。它并不一定是真正有焦点的观点。
focused -实际上具有焦点的child的后代视图
如果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));
}