我想要一个ScrollView从底部开始。任何方法吗?
scroll.fullScroll(View.FOCUS_DOWN)也应该工作。
把这个放在卷轴里。Post(可运行)
芬兰湾的科特林代码
scrollView.post {
scrollView.fullScroll(View.FOCUS_DOWN)
}
您应该在滚动中运行代码。像这样发帖:
scroll.post(new Runnable() {
@Override
public void run() {
scroll.fullScroll(View.FOCUS_DOWN);
}
});
我增加工作完美。
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();
}
Note
这个答案是一个非常老版本的android的变通方案。今天postDelayed已经没有这个bug了,你应该使用它。
当视图尚未加载时,您不能滚动。你可以“稍后”用上面的post或sleep call来做这件事,但这不是很优雅。
最好计划滚动并在下一个onLayout()中执行。示例代码如下:
https://stackoverflow.com/a/10209457/1310343
需要考虑的一件事是不设置什么。确保您的子控件,特别是EditText控件,没有RequestFocus属性集。这可能是布局中最后解释的属性之一,它将覆盖其父(布局或ScrollView)上的重力设置。
最适合我的是
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());
}
});
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);
这很有效。
芬兰湾的科特林扩展
fun ScrollView.scrollToBottom() {
val lastChild = getChildAt(childCount - 1)
val bottom = lastChild.bottom + paddingBottom
val delta = bottom - (scrollY+ height)
smoothScrollBy(0, delta)
}
这并不是问题的确切答案,但我需要在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();
}
}
});
有时滚动视图。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);
在Kotlin协程中使用there还有另一种很酷的方法。使用协程而不是具有可运行对象(post/postDelayed)的处理程序的优点是,它不会触发昂贵的线程来执行延迟操作。
launch(UI){
delay(300)
scrollView.fullScroll(View.FOCUS_DOWN)
}
将协程的HandlerContext指定为UI是很重要的,否则UI线程可能不会调用延迟的操作。
实际上,我发现调用fullScroll两次是有效果的:
myScrollView.fullScroll(View.FOCUS_DOWN);
myScrollView.post(new Runnable() {
@Override
public void run() {
myScrollView.fullScroll(View.FOCUS_DOWN);
}
});
这可能与在执行第一次(不成功的)滚动之后激活post()方法有关。我认为这种行为发生在任何之前的方法调用myScrollView之后,所以你可以尝试用其他任何可能与你相关的方法来替换第一个fullScroll()方法。
在这种情况下,我们只使用滚动。scrollTo(0, sc.getBottom())不工作,使用它使用scroll.post
例子:
scroll.post(new Runnable() {
@Override
public void run() {
scroll.fullScroll(View.FOCUS_DOWN);
}
});
这里有一些滚动到底部的其他方法
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()
如果你的滚动视图没有完成布局(例如:你滚动到底部的活动onCreate方法…)
my_scroll_view.post {
my_scroll_view.scrollToBottom()
}
为什么scroll.fullScroll(view . focus_down)即使包装在.post()中也不能工作的一个可能的原因是视图没有被布局。在这种情况下,View.doOnLayout()可能是一个更好的选择:
scroll.doOnLayout(){
scroll.fullScroll(View.FOCUS_DOWN)
}
或者,为勇敢的灵魂提供更详细的信息:https://chris.banes.dev/2019/12/03/suspending-views/
我尝试成功了。
scrollView.postDelayed(new Runnable() {
@Override
public void run() {
scrollView.smoothScrollTo(0, scrollView.getHeight());
}
}, 1000);
这招立竿见影。没有延迟。
// 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());
}
}
}
}
如果你的最低SDK是29或更高,你可以使用这个:
View childView = findViewById(R.id.your_view_id_in_the_scroll_view)
if(childView != null){
scrollview.post(() -> scrollview.scrollToDescendant(childView));
}
所有答案的组合对我来说很管用:
扩展函数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
}
扩展函数滚动底部
fun ScrollView.scrollToBottom() {
postDelayed {
smoothScrollBy(0, measureScrollHeight())
}
}
注意,最小延迟应该至少325毫秒,否则滚动将会有bug(不是滚动到整个底部)。当前高度和底部之间的增量越大,延迟时间就应该越大。
有人说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);
推荐文章
- 改变开关的“开”色
- 以编程方式将EditText的输入类型从PASSWORD更改为NORMAL,反之亦然
- 如何在隐藏和查看密码之间切换
- 在Android上调整一个大的位图文件到缩放输出文件
- 如何更改Android版本和代码版本号?
- Android Studio突然无法解析符号
- 应用程序重新启动而不是恢复
- 如何设置整个应用程序在纵向模式?
- Android中文本的阴影效果?
- 以编程方式设置TextView的布局权重
- Android -如何覆盖“后退”按钮,所以它不完成()我的活动?
- 如何从通知点击发送参数到一个活动?
- 导航目标xxx对于这个NavController是未知的
- 使用ConstraintLayout均匀间距的视图
- 文件google-services错误。模块根文件夹中缺少Json。谷歌服务插件没有它就不能正常工作。