230

我希望 ScrollView 从底部开始。有什么方法吗?

4

19 回答 19

347

您应该像这样运行 scroll.post 中的代码:

scroll.post(new Runnable() {            
    @Override
    public void run() {
           scroll.fullScroll(View.FOCUS_DOWN);              
    }
});
于 2010-12-24T04:05:43.340 回答
319

scroll.fullScroll(View.FOCUS_DOWN)也应该工作。

把这个放在一个scroll.Post(Runnable run)

Kotlin 代码

scrollView.post {
   scrollView.fullScroll(View.FOCUS_DOWN)
}
于 2010-06-20T18:41:55.287 回答
115

scroll.fullScroll(View.FOCUS_DOWN)会导致重心的变化。当有多个可聚焦视图(例如两个 EditText)时,这会带来一些奇怪的行为。这个问题还有另一种方法。

    View lastChild = scrollLayout.getChildAt(scrollLayout.getChildCount() - 1);
    int bottom = lastChild.getBottom() + scrollLayout.getPaddingBottom();
    int sy = scrollLayout.getScrollY();
    int sh = scrollLayout.getHeight();
    int delta = bottom - (sy + sh);

    scrollLayout.smoothScrollBy(0, delta);

这很好用。

Kotlin 扩展

fun ScrollView.scrollToBottom() {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)        
    smoothScrollBy(0, delta)
}
于 2016-01-19T00:36:31.603 回答
54

有时 scrollView.post 不起作用

 scrollView.post(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    });

但是如果你使用scrollView.postDelayed,它肯定会工作

 scrollView.postDelayed(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    },1000);
于 2016-07-26T19:41:06.230 回答
39

最适合我的是

scroll_view.post(new Runnable() {
     @Override
     public void run() {
         // This method works but animates the scrolling 
         // which looks weird on first load
         // scroll_view.fullScroll(View.FOCUS_DOWN);

         // This method works even better because there are no animations.
         scroll_view.scrollTo(0, scroll_view.getBottom());
     }
});
于 2014-02-27T14:59:34.707 回答
28

我增量工作完美。

    private void sendScroll(){
        final Handler handler = new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {Thread.sleep(100);} catch (InterruptedException e) {}
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        scrollView.fullScroll(View.FOCUS_DOWN);
                    }
                });
            }
        }).start();
    }

笔记

这个答案是真正旧版本的android的解决方法。今天postDelayed没有更多的错误,你应该使用它。

于 2012-01-06T21:45:55.063 回答
5

我试过成功。

scrollView.postDelayed(new Runnable() {
    @Override
    public void run() {
        scrollView.smoothScrollTo(0, scrollView.getHeight());
    }
}, 1000);
于 2020-04-18T16:49:53.320 回答
3

当视图尚未加载时,您无法滚动。您可以通过上面的帖子或睡眠电话“稍后”进行操作,但这不是很优雅。

最好计划滚动并在下一个 onLayout() 上执行。这里的示例代码:

https://stackoverflow.com/a/10209457/1310343

于 2012-05-10T09:09:08.193 回答
3

要考虑的一件事是不要设置什么。确保您的子控件,尤其是 EditText 控件,没有设置 RequestFocus 属性。这可能是布局上最后解释的属性之一,它将覆盖其父级(布局或 ScrollView)上的重力设置。

于 2013-09-10T17:40:49.280 回答
3

这是滚动到底部的其他一些方法

fun ScrollView.scrollToBottom() {
    // use this for scroll immediately
    scrollTo(0, this.getChildAt(0).height) 

    // or this for smooth scroll
    //smoothScrollBy(0, this.getChildAt(0).height)

    // or this for **very** smooth scroll
    //ObjectAnimator.ofInt(this, "scrollY", this.getChildAt(0).height).setDuration(2000).start()
}

使用

如果您的滚动视图已经布局

my_scroll_view.scrollToBottom()

如果您的滚动视图未完成布局(例如:您在 ActivityonCreate方法中滚动到底部...)

my_scroll_view.post { 
   my_scroll_view.scrollToBottom()          
}
于 2019-04-03T05:39:09.713 回答
1

不完全是问题的答案,但我需要在 EditText 获得焦点后立即向下滚动。然而,接受的答案会使 ET 也立即失去焦点(对于我假设的 ScrollView)。

我的解决方法如下:

emailEt.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if(hasFocus){
            Toast.makeText(getActivity(), "got the focus", Toast.LENGTH_LONG).show();
            scrollView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    scrollView.fullScroll(ScrollView.FOCUS_DOWN);
                }
            }, 200);
        }else {
            Toast.makeText(getActivity(), "lost the focus", Toast.LENGTH_LONG).show();
        }
    }
});
于 2016-06-20T23:30:37.337 回答
1

我实际上发现调用 fullScroll 两次可以解决问题:

myScrollView.fullScroll(View.FOCUS_DOWN);

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

它可能与执行第一次(不成功)滚动后立即激活 post() 方法有关。我认为这种行为发生在之前对 myScrollView 的任何方法调用之后,因此您可以尝试将第一个 fullScroll() 方法替换为可能与您相关的任何其他方法。

于 2019-01-08T18:07:53.533 回答
0

使用 Kotlin 协程还有另一种很酷的方法。与具有可运行(post/postDelayed)的 Handler 相比,使用协程的优点是它不会启动昂贵的线程来执行延迟操作。

launch(UI){
    delay(300)
    scrollView.fullScroll(View.FOCUS_DOWN)
}

将协程的 HandlerContext 指定为 UI 很重要,否则可能不会从 UI 线程调用延迟的操作。

于 2018-04-09T10:44:56.307 回答
0

在那些情况下,只使用scroll.scrollTo(0, sc.getBottom())不起作用,使用scroll.post

例子:

scroll.post(new Runnable() {
  @Override
  public void run() {
  scroll.fullScroll(View.FOCUS_DOWN);
  } 
});
于 2019-02-27T18:42:20.083 回答
0

scroll.fullScroll(View.FOCUS_DOWN)为什么即使包裹在其中也可能不起作用的一个可能原因.post()是视图没有布局。在这种情况下, View.doOnLayout()可能是一个更好的选择:

scroll.doOnLayout(){
    scroll.fullScroll(View.FOCUS_DOWN)
}

或者,为勇敢的灵魂提供更详细的内容:https ://chris.banes.dev/2019/12/03/suspending-views/

于 2020-04-14T22:15:08.287 回答
0

立即起作用。不延误。

// wait for the scroll view to be laid out
scrollView.post(new Runnable() {
  public void run() {
    // then wait for the child of the scroll view (normally a LinearLayout) to be laid out
    scrollView.getChildAt(0).post(new Runnable() {
      public void run() {
        // finally scroll without animation
        scrollView.scrollTo(0, scrollView.getBottom());
      }
    }
  }
}
于 2020-07-09T08:09:51.797 回答
0

如果您的最低 SDK 为 23 或更高版本,您可以使用:

View childView = findViewById(R.id.your_view_id_in_the_scroll_view)
if(childView != null){
  scrollview.post(() -> scrollview.scrollToDescendant(childView));
}
于 2021-02-15T11:23:00.840 回答
0

所有答案的组合对我有用:

扩展功能 PostDelayed

private fun ScrollView.postDelayed(
    time: Long = 325, // ms
    block: ScrollView.() -> Unit
) {
    postDelayed({block()}, time)
}

扩展函数 measureScrollHeight

fun ScrollView.measureScrollHeight(): Int {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)
    return delta
}

扩展功能 ScrolltoBottom

fun ScrollView.scrollToBottom() {
    postDelayed {
        smoothScrollBy(0, measureScrollHeight())
    }
}

请注意,最小延迟应至少为 325 毫秒,否则滚动会出错(不会滚动到整个底部)。当前高度和底部之间的增量越大,延迟时间应该越大。

于 2021-06-22T14:34:46.443 回答
0

这里有人说 scrollView.post 不起作用。

如果您不想使用 scrollView.postDelayed,另一种选择是使用侦听器。这是我在另一个用例中所做的:

ViewTreeObserver.OnPreDrawListener viewVisibilityChanged = new ViewTreeObserver.OnPreDrawListener() {
    @Override
    public boolean onPreDraw() {
        if (my_view.getVisibility() == View.VISIBLE) {
            scroll_view.smoothScrollTo(0, scroll_view.getHeight());
        }
        return true;
    }
};

您可以通过以下方式将其添加到您的视图中:

my_view.getViewTreeObserver().addOnPreDrawListener(viewVisibilityChanged);
于 2021-10-25T18:22:32.417 回答