Horizo​​ntalScrollView:自动滚动到添加新视图时结束?

我有一个包含LinearLayout的Horizo​​ntalScrollView。 在屏幕上,我有一个button,将在运行时将新的视图添加到LinearLayout,我想滚动视图滚动到列表的末尾添加一个新的视图时。

我几乎有它的工作 – 除了它总是滚动一个视图短的最后一个视图。 它似乎是滚动,而不是首先计算包含新视图。

在我的应用程序中,我使用了一个自定义的View对象,但是我做了一个使用ImageView并且具有相同症状的小型testing应用程序。 我尝试了各种东西像requestLayout()布局和ScrollView,我试图scrollTo(Integer.MAX_VALUE),它滚动到netherverse :)我违反了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_width="fill_parent" android:layout_height="fill_parent"> <HorizontalScrollView android:id="@+id/scroller" android:layout_width="wrap_content" android:layout_height="wrap_content" android:scrollbarSize="50px"> <LinearLayout android:id="@+id/list" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="4px"/> </HorizontalScrollView> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_gravity="center"> <Button android:id="@+id/addButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:paddingLeft="80px" android:paddingRight="80px" android:paddingTop="40px" android:paddingBottom="40px" android:text="Add"/> </LinearLayout> </LinearLayout> 

我认为有一个时间问题。 添加视图时布局没有完成。 这是要求和做一段时间后。 在添加视图后立即调用fullScroll时,linearlayout的宽度没有机会展开。

尝试更换:

 s.fullScroll(HorizontalScrollView.FOCUS_RIGHT); 

有:

 s.postDelayed(new Runnable() { public void run() { s.fullScroll(HorizontalScrollView.FOCUS_RIGHT); } }, 100L); 

短暂的延迟应该给系统足够的时间来解决。

PS直接在UI循环的当前迭代之后延迟滚动可能就足够了。 我没有testing过这个理论,但是如果这是正确的,那就足够了:

 s.post(new Runnable() { public void run() { s.fullScroll(HorizontalScrollView.FOCUS_RIGHT); } }); 

我更喜欢这个,因为引入一个任意的延迟对我来说似乎很难(尽pipe这是我的build议)。

只是另一个消化,因为这个问题帮了我很多:)。

当视图完成其布局阶段后,您可以放置​​一个侦听器,在完成fullScroll之后,尽pipe您需要扩展该类。

我只是这样做,因为我想滚动到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(); } } 

我同意@monxalo和@ granko87,更好的方法是用一个监听器,而不是假设布局将会完成,如果我们让任意的时间过去。

如果像我一样,你不需要使用一个自定义的Horizo​​ntalScrollView子类,你可以添加一个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); } }); 

使用View方法smoothScrollTo

 postDelayed(new Runnable() { public void run() { scrollView.smoothScrollTo(newView.getLeft(), newView.getTop()); } }, 100L); 

你需要放入一个可运行的,所以你给布局过程的时间来定位新的视图

这就是我所做的。

 //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); } }); } 

我认为最好的方法是由monxalo发布,因为你不知道要花多less时间才能完成布局。 我试了一下,它完美的作品。 唯一的区别是,我只添加了一行到我的自定义水平滚动视图:

 @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); } 

使用下面的代码水平滚动视图{ 滚动到右侧 }

 view.post(new Runnable() { @Override public void run() { ((HorizontalScrollView) Iview .findViewById(R.id.hr_scroll)) .fullScroll(HorizontalScrollView.FOCUS_RIGHT); } });