web-dev-qa-db-ja.com

Horizo​​ntalScrollView:新しいビューが追加されたときに終了する自動スクロール?

LinearLayoutを含むHorizo​​ntalScrollViewがあります。画面には、実行時に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>
49
Rick Barkhouse

タイミングの問題があると思います。ビューが追加されるとき、レイアウトは行われません。それは要求され、少し後に行われます。ビューを追加した直後に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);
    }
});

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

128
Ted Hopp

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

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

ビューのレイアウトフェーズが終了したらリスナーを配置し、そのためにクラスを拡張する必要があるが、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();
    }
}
12
monxalo

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

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

新しいビューを配置するためにレイアウトプロセスに時間をかけるために、実行可能ファイルを配置する必要があります

4

これは私がやったことです。

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

水平スクロールビューに次のコードを使用{右にスクロール}

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

レイアウトが完了するまでにどれくらいの時間がかかるかわからないため、最善のアプローチは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);
}
1
granko87

Viewに子ViewGroupをすぐに追加することはできません。そのため、他の保留中のタスクが完了した後に実行されるRunnableを投稿する必要があります。

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

horizontalScrollView.post(new Runnable() {
    @Override
    public void run() {
        horizontalScrollView.fullScroll(View.FOCUS_RIGHT);
    }
});
0
Nabin Bhandari

これは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)
0
Gabriel