web-dev-qa-db-ja.com

Android scrollview onScrollChanged

スクロールビュー内のテキストビューに固定コンテンツがあります。ユーザーが特定の位置にスクロールしたら、アクティビティを開始するか、Toastをトリガーしたいと思います。

<ScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
 Android:layout_width="fill_parent" Android:layout_height="fill_parent"
 Android:id="@+id/scroller">
 <LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
  Android:orientation="vertical" Android:layout_width="fill_parent"
  Android:layout_height="fill_parent">
  <TextView Android:layout_width="fill_parent" Android:id="@+id/story"
   Android:layout_height="wrap_content" Android:text="@string/lorem"
   Android:gravity="fill" />
 </LinearLayout>
</ScrollView>

私の問題は、保護されたメソッドonScrollChangedを実装して、スクロールビューの位置を見つけることです。

私は this の答えを見つけました。投稿したリンクに見られるように、インターフェースを宣言したり、スクロールビューに乗ったりするよりも、これに対する簡単な解決策はありますか?

22
SteD

番号。

ScrollViewは、スクロールイベントのリスナーや、ユーザーがスクロールした距離を確認する方法さえ提供しないため、リンクで提案されていることを行う必要があります。

13
Computerish

ScrollViewをサブクラス化するよりもはるかに簡単な方法があります。 ViewTreeObserverScrollViewオブジェクトを使用して、スクロールをリッスンできます。

ViewTreeObserverオブジェクトはScrollViewの有効期間中に変更される可能性があるため、OnTouchListenerを取得するにはScrollViewViewTreeObserverを登録する必要があります_スクロール時。

final ViewTreeObserver.OnScrollChangedListener onScrollChangedListener = new
                           ViewTreeObserver.OnScrollChangedListener() {

    @Override
    public void onScrollChanged() {
        //do stuff here 
    }
};

final ScrollView scrollView = (ScrollView) findViewById(R.id.scroller);
scrollView.setOnTouchListener(new View.OnTouchListener() {
    private ViewTreeObserver observer;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (observer == null) {
            observer = scrollView.getViewTreeObserver();
            observer.addOnScrollChangedListener(onScrollChangedListener);
        }
        else if (!observer.isAlive()) {
            observer.removeOnScrollChangedListener(onScrollChangedListener);
            observer = scrollView.getViewTreeObserver();
            observer.addOnScrollChangedListener(onScrollChangedListener);
        }

        return false;
    }
});
48

この質問はかなり古いですが、誰かが立ち寄った場合(私のように):

API 23以降、AndroidのViewにはOnScrollChangeListenermatching setter があります。

サポートライブラリの NestedScrollView は、そのAPIレベルの前でもスクロールリスナーの設定もサポートしています。私の知る限り、NestedScrollViewは問題なく通常のScrollViewの代わりとして使用できます。

9
Lovis

実際、ユーザーがどれだけスクロールしたかを知る方法があります。 ScrollViewのgetScrollY()メソッドはそれを示しています。

8
tulio84z

ScrollViewを拡張しました。 このリンク が役立つ場合があります。

class MyScroll extends ScrollView {
    boolean onTop=true;
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        //Log.d(TAG, "scroll changed: " + this.getTop() + " "+t);
        if(t <= 0){
            onTop = true;
            //Log.d(TAG, "scroll top: " + t);
            super.onScrollChanged(l, t, oldl, oldt);
            return;
            // reaches the top end
        }
        onTop = false;

        View view = (View) getChildAt(getChildCount()-1);
        int diff = (view.getBottom()-(getHeight()+getScrollY()+view.getTop()));// Calculate the scrolldiff
        if( diff <= 0 ){
            // if diff is zero, then the bottom has been reached
        }
        super.onScrollChanged(l, t, oldl, oldt);
    }
}
2
Ovechkin Pavel

NestedScrollViewはAndroid.widget.ScrollViewと同様ですが、Androidの新旧両方のバージョンでネストされたスクロールの親と子の両方として機能することをサポートします。

1番目-ScrollViewの代わりにNestedScrollViewバインディングを使用します

2nd-Scrollリスナーをこのように設定して、headerViewの軸Yの動きを例で検出します

    nestedScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {

        @Override
        public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
            Log.d(TAG, "onScrollChangeForY - scrollY: " + scrollY + " oldScrollY: " + oldScrollY);

            int MOVE = -1, SCROLL_UP = 0, SCROLL_DOWN = 1;
            float initialPositionY = headerView.getY();

            MOVE = scrollY > oldScrollY ? SCROLL_UP : SCROLL_DOWN;

            if (MOVE == SCROLL_UP) {

                int incrementY = scrollY - oldScrollY;

                headerView.setY(initialPositionY - incrementY);

            } else {

                int incrementY = oldScrollY - scrollY;

                headerView.setY(initialPositionY + incrementY);
            }
        }
    });
1

このトリガーを使用して、ToastまたはStart Activityを表示できます

 scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
             // do something when Scroll  
        }
    });
0
yousef

NestedScrollNestedScroll.setOnScrollChangeListener()を使用するだけです。

0
Kai Wang

ready for use component があり、Androidの任意のビューのスクロールイベントをリッスンするのに役立ちます。内部的にこのコンポーネントは、古いAndroid API(Shubhadeep Chaudhuriの回答で提案されたものと同様)のデバイスにViewTreeObserverスクロールイベントリスナーを追加し、新しいAndroid = API(APIレベル23+)。

0
Denis

API 23以降Android M、OnScrollChangeListenerを使用できます。

 scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
        @Override
        public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
            //work with parameters
        }
    });
0

このコードを使用して、上下スクロールを検出できます

scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
            int lastScroll=0;
            @Override
            public void onScrollChanged() {
                int scrollY = scrollView.getScrollY(); // For ScrollView herzontial use getScrollX()

                if (scrollY > lastScroll ) {
                    Log.e("scroll","down scroll"+scrollY);
                } else if (scrollY < lastScroll ) {
                    Log.e("scroll","up scroll"+scrollY);
                }
                lastScroll=scrollY;
            }
        });
0