58

LinearLayoutを含むHorizo​​ntalScrollViewがあります。画面には、実行時に新しいビューをLinearLayoutに追加するボタンがあり、新しいビューが追加されたときにスクロールビューをリストの最後までスクロールしたいと思います。

私はほとんどそれを機能させています-それが常に最後のビューの1つ手前のビューをスクロールすることを除いて。最初に新しいビューの包含を計算せずにスクロールしているようです。

私のアプリではカスタム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_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>
4

9 に答える 9

142

タイミングの問題があると思います。ビューが追加されたとき、レイアウトは行われません。それは要求され、しばらくしてから行われます。ビューを追加した直後にfullScrollを呼び出すと、linearlayoutの幅が拡大する機会がありませんでした。

交換してみてください:

s.fullScroll(HorizontalScrollView.FOCUS_RIGHT);

と:

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

短い遅延は、システムが落ち着くのに十分な時間を与えるはずです。

PS UIループの現在の反復が終了するまで、スクロールを単に遅らせるだけで十分な場合があります。私はこの理論をテストしていませんが、それが正しければ、次のことを行うだけで十分です。

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

任意の遅延を導入することは私にはハッキーに思えるので、私はこれがより好きです(それが私の提案であったとしても)。

于 2011-01-18T04:44:04.823 に答える
18

@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);
    }
});
于 2015-03-03T19:36:23.837 に答える
12

この質問は私を大いに助けたので、ちょうど別の推測:)。

ビューがレイアウトフェーズを終了したときにリスナーを配置できます。そのためにクラスを拡張する必要がありますが、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();
    }
}
于 2011-03-16T15:54:21.977 に答える
4

ViewメソッドsmoothScrollToを使用します

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

新しいビューを配置するためのレイアウトプロセスに時間をかけるために、ランナブルを配置する必要があります

于 2013-02-04T11:22:06.053 に答える
3

水平スクロールビューには以下のコードを使用してください{右にスクロール}

view.post(new Runnable() {
                @Override
                public void run() {
                    ((HorizontalScrollView) Iview
                            .findViewById(R.id.hr_scroll))
                            .fullScroll(HorizontalScrollView.FOCUS_RIGHT);
                }
            });
于 2014-08-24T00:03:29.643 に答える
3

これが私がしたことです。

//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);
            }
     });
   }
于 2015-02-08T15:01:55.003 に答える
1

レイアウトが完了するまでにどれくらいの時間がかかるかわからないので、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);
}
于 2013-05-15T12:17:58.157 に答える
0

Viewはすぐにに追加されない場合がありますViewGroup。したがってRunnable、他の保留中のタスクが完了した後に実行されるを投稿する必要があります。

したがって、追加した後View、次を使用します。

horizontalScrollView.post(new Runnable() {
    @Override
    public void run() {
        horizontalScrollView.fullScroll(View.FOCUS_RIGHT);
    }
});
于 2018-03-06T07:25:34.373 に答える
0

これは、kotlinでの3つのImageViewの私の方法です。

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)
于 2019-05-13T20:01:36.280 に答える