我有一个很长的活动与滚动视图。这是一个包含用户必须填写的各种字段的表单。我的表单中有一个复选框,当用户检查它时,我想滚动到视图的特定部分。有没有办法以编程方式滚动到EditText对象(或任何其他视图对象)?
另外,我知道这可以使用X和Y坐标,但我想避免这样做,因为表单可能会因用户而异。
答案 0 :(得分:396)
private final void focusOnView(){
your_scrollview.post(new Runnable() {
@Override
public void run() {
your_scrollview.scrollTo(0, your_EditBox.getBottom());
}
});
}
答案 1 :(得分:50)
如果你想将视图滚动到滚动视图的中心,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
,更改x
输入的y
和smoothScroll
位置。并使用view.getTop()
代替view.getLeft()
和view.getBottom()
代替v.getRight()
。
:)
答案 2 :(得分:43)
这对我很有用:
targetView.getParent().requestChildFocus(targetView,targetView);
public void RequestChildFocus(View child,View focused)
child - 此ViewParent的子项需要焦点。该视图将包含焦点视图。实际上并不一定是关注焦点。
专注 - 作为实际拥有焦点的儿童后代的视图
答案 3 :(得分:24)
在我看来,滚动到给定矩形的最佳方法是通过View.requestRectangleOnScreen(Rect, Boolean)
。您应该在想要滚动到的View
上调用它并传递您想要在屏幕上显示的本地矩形。第二个参数应为false
以便平滑滚动,true
用于立即滚动。
final Rect rect = new Rect(0, 0, view.getWidth(), view.getHeight());
view.requestRectangleOnScreen(rect, false);
答案 4 :(得分: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());
}
});
}
}
答案 5 :(得分:10)
您应该关注TextView
请求:
mTextView.requestFocus();
答案 6 :(得分:7)
我的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();
答案 7 :(得分:4)
另一个变种是:
scrollView.postDelayed(new Runnable()
{
@Override
public void run()
{
scrollView.smoothScrollTo(0, img_transparent.getTop());
}
}, 2000);
或者您可以使用post()
方法。
答案 8 :(得分:4)
我知道要想获得更好的答案可能为时已晚,但是理想的完美解决方案必须是定位器之类的系统。我的意思是,当系统为“编辑器”字段定位时,它会将字段放置在键盘上方,因此,根据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);
}
});
}
}
});
如果您想将此块用于所有 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.
答案 9 :(得分:2)
参考:https://stackoverflow.com/a/6438240/2624806
以下工作要好得多。
mObservableScrollView.post(new Runnable() {
public void run() {
mObservableScrollView.fullScroll([View_FOCUS][1]);
}
});
答案 10 :(得分:2)
答案 11 :(得分:2)
如果ScrollView是ChildView的直接父级,则上述答案将正常工作。如果您的ChildView被包装在ScrollView中的另一个ViewGroup中,则将导致意外行为,因为View.getTop()获得相对于其父项的位置。在这种情况下,您需要执行以下操作:
getRolesSubject.next(mockResponse);
答案 12 :(得分:1)
我认为我使用
找到了更优雅,更不容易出错的解决方案没有涉及数学,与其他提议的解决方案相反,它将正确处理向上和向下滚动。
/**
* Will scroll the {@code scrollView} to make {@code viewToScroll} visible
*
* @param scrollView parent of {@code scrollableContent}
* @param scrollableContent a child of {@code scrollView} whitch holds the scrollable content (fills the viewport).
* @param viewToScroll a child of {@code scrollableContent} to whitch will scroll the the {@code scrollView}
*/
void scrollToView(ScrollView scrollView, ViewGroup scrollableContent, View viewToScroll) {
Rect viewToScrollRect = new Rect(); //coordinates to scroll to
viewToScroll.getHitRect(viewToScrollRect); //fills viewToScrollRect with coordinates of viewToScroll relative to its parent (LinearLayout)
scrollView.requestChildRectangleOnScreen(scrollableContent, viewToScrollRect, false); //ScrollView will make sure, the given viewToScrollRect is visible
}
最好将其包装到postDelayed
中,以使其更可靠,以防ScrollView
暂时更改
/**
* Will scroll the {@code scrollView} to make {@code viewToScroll} visible
*
* @param scrollView parent of {@code scrollableContent}
* @param scrollableContent a child of {@code scrollView} whitch holds the scrollable content (fills the viewport).
* @param viewToScroll a child of {@code scrollableContent} to whitch will scroll the the {@code scrollView}
*/
private void scrollToView(final ScrollView scrollView, final ViewGroup scrollableContent, final View viewToScroll) {
long delay = 100; //delay to let finish with possible modifications to ScrollView
scrollView.postDelayed(new Runnable() {
public void run() {
Rect viewToScrollRect = new Rect(); //coordinates to scroll to
viewToScroll.getHitRect(viewToScrollRect); //fills viewToScrollRect with coordinates of viewToScroll relative to its parent (LinearLayout)
scrollView.requestChildRectangleOnScreen(scrollableContent, viewToScrollRect, false); //ScrollView will make sure, the given viewToScrollRect is visible
}
}, delay);
}
答案 13 :(得分:1)
yourScrollView.smoothScrollTo(0, yourEditText.getTop());
就去做吧;)
答案 14 :(得分:0)
以下是我正在使用的内容:
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);
}
这将获得显示视图底部所需的滚动量,包括该视图底部的任何边距。
答案 15 :(得分:0)
垂直滚动,适用于表格。答案基于Ahmadalibaloch横向滚动。
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));
}
});
}
答案 16 :(得分:0)
我的解决方案是:
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]);
答案 17 :(得分:0)
如果scrlMain是您的NestedScrollView,则使用以下内容,
scrlMain.post(new Runnable() {
@Override
public void run() {
scrlMain.fullScroll(View.FOCUS_UP);
}
});
答案 18 :(得分:0)
您可以像这样使用ObjectAnimator
:
ObjectAnimator.ofInt(yourScrollView, "scrollY", yourView.getTop()).setDuration(1500).start();
答案 19 :(得分:0)
Que:有没有办法以编程方式将滚动视图滚动到特定的edittext?
Ans:Recyclerview中的嵌套滚动视图上一个位置添加了记录数据。
adapter.notifyDataSetChanged();
nested_scroll.setScrollY(more Detail Recycler.getBottom());
Is there a way to programmatically scroll a scroll view to a specific edit text?
答案 20 :(得分:0)
根据Sherif的回答,以下内容最适合我的用例。值得注意的更改是getTop()
而非getBottom()
和smoothScrollTo()
而非scrollTo()
。
private void scrollToView(final View view){
final ScrollView scrollView = findViewById(R.id.bookmarksScrollView);
if(scrollView == null) return;
scrollView.post(new Runnable() {
@Override
public void run() {
scrollView.smoothScrollTo(0, view.getTop());
}
});
}
答案 21 :(得分:0)
就我而言,那不是EditText
,而是googleMap
。
它就像这样成功。
private final void focusCenterOnView(final ScrollView scroll, final View view) {
new Handler().post(new Runnable() {
@Override
public void run() {
int centreX=(int) (view.getX() + view.getWidth() / 2);
int centreY= (int) (view.getY() + view.getHeight() / 2);
scrollView.smoothScrollBy(centreX, centreY);
}
});
}
答案 22 :(得分:0)
如果你想在软键盘打开时滚动到一个视图,那么它可能会有点棘手。
到目前为止,我得到的最佳解决方案是结合使用 inset 回调和 requestRectangleOnScreen
方法。
首先,您需要设置插入回调:
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
})
}
}
我们正在根视图上设置回调以确保我们被调用。 Insets 可能会在我们所讨论的视图收到它们之前被消耗掉,所以我们必须在这里做额外的工作。
现在几乎很容易:
doOnApplyWindowInsetsInRoot { _, _, _ ->
post {
if (viewInQuestion.hasFocus()) {
requestRectangleOnScreen(Rect(0, 0, width, height))
}
}
}
您可以摆脱焦点检查。它用于限制对 requestRectangleOnScreen
的调用次数。我使用 post
在可滚动父级计划滚动到焦点视图后运行操作。
答案 23 :(得分:0)
检查Android源代码,您会发现已经存在android:configChanges=...
- ScrollView
的成员函数 - 它完全符合要求。不幸的是,这个功能是出于标记scrollToChild(View)
的一些不明原因。基于该函数,我编写了以下函数,该函数查找指定为参数的private
上方的第一个ScrollView
并滚动它以使其在View
中可见:
ScrollView
答案 24 :(得分:0)
如果有人正在寻找 Kotlin 版本,您可以使用扩展功能来做到这一点
fun ScrollView.scrollToChild(view: View, onScrolled: (() -> Unit)? = null) {
view.requestFocus()
val scrollBounds = Rect()
getHitRect(scrollBounds)
if (!view.getLocalVisibleRect(scrollBounds)) {
findViewTreeLifecycleOwner()?.lifecycleScope?.launch(Dispatchers.Main) {
smoothScrollTo(0, view.bottom - 40)
onScrolled?.invoke()
}
}
}
有一个小回调可以让你在滚动后做一些事情。