HorizontalScrollView:添加新视图时自动滚动到结束?
Posted
技术标签:
【中文标题】HorizontalScrollView:添加新视图时自动滚动到结束?【英文标题】:HorizontalScrollView: auto-scroll to end when new Views are added? 【发布时间】:2011-06-10 20:46:40 【问题描述】:我有一个包含 LinearLayout 的 HorizontalScrollView。在屏幕上,我有一个 Button,它将在运行时将新视图添加到 LinearLayout,并且我希望滚动视图在添加新视图时滚动到列表的末尾。
我几乎让它工作了 - 除了它总是在最后一个视图之外滚动一个视图。它似乎在没有先计算包含新视图的情况下滚动。
在我的应用程序中,我使用的是自定义 View 对象,但我制作了一个使用 ImageView 并具有相同症状的小型测试应用程序。我在 Layout 和 ScrollView 上尝试了各种类似 requestLayout() 的方法,我尝试了 scrollTo(Integer.MAX_VALUE) 并且它滚动到了下界:) 我是否违反了 UI 线程问题或其他问题?
瑞克======
public class Main extends Activity
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button b = (Button) findViewById(R.id.addButton);
b.setOnClickListener(new AddListener());
add();
private void add()
LinearLayout l = (LinearLayout) findViewById(R.id.list);
HorizontalScrollView s =
(HorizontalScrollView) findViewById(R.id.scroller);
ImageView i = new ImageView(getApplicationContext());
i.setImageResource(android.R.drawable.btn_star_big_on);
l.addView(i);
s.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
private class AddListener implements View.OnClickListener
@Override
public void onClick(View v)
add();
布局 XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_
android:layout_>
<HorizontalScrollView
android:id="@+id/scroller"
android:layout_
android:layout_
android:scrollbarSize="50px">
<LinearLayout
android:id="@+id/list"
android:layout_
android:layout_
android:padding="4px"/>
</HorizontalScrollView>
<LinearLayout
android:layout_
android:layout_
android:layout_gravity="center">
<Button
android:id="@+id/addButton"
android:layout_
android:layout_
android:layout_gravity="center"
android:paddingLeft="80px"
android:paddingRight="80px"
android:paddingTop="40px"
android:paddingBottom="40px"
android:text="Add"/>
</LinearLayout>
</LinearLayout>
【问题讨论】:
【参考方案1】:我认为存在时间问题。添加视图时未完成布局。它被请求并在短时间内完成。当你在添加视图后立即调用 fullScroll 时,线性布局的宽度还没有机会扩大。
尝试替换:
s.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
与:
s.postDelayed(new Runnable()
public void run()
s.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
, 100L);
短暂的延迟应该给系统足够的时间来稳定。
附:简单地将滚动延迟到 UI 循环的当前迭代之后可能就足够了。我没有测试过这个理论,但如果它是正确的,那么做以下事情就足够了:
s.post(new Runnable()
public void run()
s.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
);
我更喜欢这个,因为引入任意延迟对我来说似乎很老套(尽管这是我的建议)。
【讨论】:
Ted 完全做到了,非常感谢,这已经困扰我好几天了! :) 嗨 Ted....当我尝试使用上面的代码时,它显示错误无法解析方法'postDelayed(java.lang.runnable, long)'...请帮助我.. .. @VinitVikash - 这是View
类中的一个方法。你可能需要做s.postDelayed(...)
。或者,创建一个Handler
并使用它的postDelayed()
方法。
new Handler().postDelayed()
如果你不知道如何使用postDelayed()
@PratikButani - 这行得通,但是将Handler
分配一次作为一个字段并使用它会更有效,而不是每次都动态创建一个。但是,由于我们已经有了视图引用 s
,所以最好只使用 s.postDelayed(...)
,这很好地回避了对我们自己的 Handler
的需求。【参考方案2】:
我同意 @monxalo 和 @granko87 的观点,即更好的方法是使用监听器,而不是假设如果我们让任意时间过去,布局就会完成。
如果你像我一样不需要使用自定义的 HorizontalScrollView 子类,你可以添加一个 OnLayoutChangeListener 来保持简单:
mTagsScroller.addOnLayoutChangeListener(new View.OnLayoutChangeListener()
@Override
public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)
mTagsScroller.removeOnLayoutChangeListener(this);
mTagsScroller.fullScroll(View.FOCUS_RIGHT);
);
【讨论】:
这也是我想出的解决方案。更少的代码,做的工作。 这是迄今为止问题的正确答案。等待任何随机时间都是无稽之谈。等待布局引擎完成它的工作是正确的。【参考方案3】:只是另一个建议,因为这个问题对我帮助很大:)。
您可以在视图完成布局阶段后放置一个侦听器,然后在执行 fullScroll 尽管您需要为此扩展类。
我这样做只是因为我想在 onCreate() 之后滚动到某个部分,以避免从起点到滚动点的闪烁。
类似:
public class PagerView extends HorizontalScrollView
private OnLayoutListener mListener;
///...
private interface OnLayoutListener
void onLayout();
public void fullScrollOnLayout(final int direction)
mListener = new OnLayoutListener()
@Override
public void onLayout()
fullScroll(direction)
mListener = null;
;
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
super.onLayout(changed, l, t, r, b);
if(mListener != null)
mListener.onLayout();
【讨论】:
【参考方案4】:使用View方法smoothScrollTo
postDelayed(new Runnable()
public void run()
scrollView.smoothScrollTo(newView.getLeft(), newView.getTop());
, 100L);
您需要放入一个可运行文件,以便为布局过程留出时间来定位新视图
【讨论】:
不适合我。 View#getTop() 返回相对于父级的位置,因此这在更多嵌套布局中不起作用【参考方案5】:水平滚动视图使用下面的代码向右滚动
view.post(new Runnable()
@Override
public void run()
((HorizontalScrollView) Iview
.findViewById(R.id.hr_scroll))
.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
);
【讨论】:
【参考方案6】:这就是我所做的。
//Observe for a layout change
ViewTreeObserver viewTreeObserver = yourLayout.getViewTreeObserver();
if (viewTreeObserver.isAlive())
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
@Override
public void onGlobalLayout()
yourHorizontalScrollView.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
);
【讨论】:
【参考方案7】:我认为最好的方法是 monxalo 发布的方法,因为您无法知道布局完成需要多长时间。我试过了,效果很好。唯一的区别是,我只在自定义水平滚动视图中添加了一行:
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
super.onLayout(changed, l, t, r, b);
this.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
【讨论】:
我不认为时间量是相关的。问题是滚动不应该发生在 UI 线程循环的当前迭代中。当前迭代完成后,视图层次结构应该是最新的并进行布局。【参考方案8】:子 View
可能不会立即添加到 ViewGroup
中。因此需要发布一个Runnable
,它将在其他待处理任务完成后运行。
所以在添加View
之后,使用:
horizontalScrollView.post(new Runnable()
@Override
public void run()
horizontalScrollView.fullScroll(View.FOCUS_RIGHT);
);
【讨论】:
【参考方案9】:这是我在 kotlin 中使用 3 个 ImageViews 的方式:
var p1 = true; var p2 = false; var p3 = false
val x = -55
val handler = Handler()
handler.postDelayed(object : Runnable
override fun run()
if (p1)
mainView.picsScrollViewID.smoothScrollTo(mainView.bigPic1ID.x.toInt() + x, 0)
p1 = false
p2 = true
p3 = false
else if(p2)
mainView.picsScrollViewID.smoothScrollTo(mainView.bigPic2ID.x.toInt() + x, 0)
p1 = false
p2 = false
p3 = true
else if(p3)
mainView.picsScrollViewID.smoothScrollTo(mainView.bigPic3ID.x.toInt() + x, 0)
p1 = true
p2 = false
p3 = false
handler.postDelayed(this, 2000)
, 1400)
【讨论】:
以上是关于HorizontalScrollView:添加新视图时自动滚动到结束?的主要内容,如果未能解决你的问题,请参考以下文章
HorizontalScrollView 以编程方式滚动而没有焦点
如何修复 HorizontalScrollView 的滚动宽度?
DrawerLayout 与 HorizontalScrollView 进入内容菜单
HorizontalScrollView 中的自定义视图不滚动