LinearLayoutを含むHorizontalScrollViewがあります。画面には、実行時にLinearLayoutに新しいビューを追加するボタンがあります。新しいビューが追加されたときに、スクロールビューをリストの最後までスクロールさせたいです。
私はそれをほとんど動作させています-最後のビューの前に常に1つのビューをスクロールすることを除いて。新しいビューの包含を最初に計算せずにスクロールしているようです。
私のアプリでは、カスタムビューオブジェクトを使用していますが、ImageViewを使用し、同じ症状を持つ小さなテストアプリケーションを作成しました。 LayoutとScrollViewの両方でrequestLayout()のようなさまざまなことを試しました。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);
短い遅延により、システムが安定するのに十分な時間が与えられます。
追伸UIループの現在の反復の後まで、スクロールを単に遅延させるだけで十分な場合があります。私はこの理論をテストしていませんが、それが正しい場合は、次のことを行うだけで十分です。
s.post(new Runnable() {
public void run() {
s.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
}
});
任意の遅延を導入することは私にとってはハッキーだと思われるため(これは私の提案でしたが)、私はこれがより好きです。
@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);
}
});
この質問は私を大いに助けたので、ちょうど別の提案:)。
ビューのレイアウトフェーズが終了したらリスナーを配置し、そのためにクラスを拡張する必要があるが、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();
}
}
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);
}
});
}
水平スクロールビューに次のコードを使用{右にスクロール}
view.post(new Runnable() {
@Override
public void run() {
((HorizontalScrollView) Iview
.findViewById(R.id.hr_scroll))
.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
}
});
レイアウトが完了するまでにどれくらいの時間がかかるかわからないため、最善のアプローチはmonxaloによって投稿されたものだと思います。私はそれを試してみましたが、完全に機能します。唯一の違いは、カスタムの水平スクロールビューに1行だけ追加したことです。
@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
に子ViewGroup
をすぐに追加することはできません。そのため、他の保留中のタスクが完了した後に実行されるRunnable
を投稿する必要があります。
View
を追加した後、次を使用します。
horizontalScrollView.post(new Runnable() {
@Override
public void run() {
horizontalScrollView.fullScroll(View.FOCUS_RIGHT);
}
});
これは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)