ScrollViewのonScrollListenerを使用できますか?


140

私が使用していHorizontalScrollViewレイアウトで、私は、スクロールの開始と終了点に達しているユーザーを識別する必要があります。

以下のためにListView私が試してみましたがonScrollListener、スクロールの開始と終了ポイントを見つけることが可能です。

私も同じようにしようとしましたが、Scrollview不可能のようです。私が必要とするものを達成するために他に可能な方法はありますか?


3
可能です。user2695685の回答を参照してください。要するに中で次のようにonStart:トリックを行いますhsv.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {@Override public void onScrollChanged() {Log.i(TAG,"scroll:"+hsv.getScrollX());}});ONSTARTで()hsvHorizontalScrollView作品を。
JohnnyLambada 14年

役に立つ答えをだれでも受け入れます。他に自分の答えを投稿した場合..
Ranjith Kumar

12
AndroidでScrollViewを使用したスクロールイベントの検出が難しいのはなぜですか?これはナッツイモです。
勤務

回答:


389

Viewのすべてのインスタンスがを呼び出しますgetViewTreeObserver()。のインスタンスを保持しているときに、メソッドを使用してにインスタンスをViewTreeObserver追加できます。OnScrollChangedListener()addOnScrollChangedListener()

このクラスの詳細については、こちらをご覧ください

すべてのスクロールイベントを認識できますが、座標はありません。ただし、リスナーを使用して、getScrollY()またはgetScrollX()リスナー内から取得できます。

scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {
    @Override
    public void onScrollChanged() {
        int scrollY = rootScrollView.getScrollY(); // For ScrollView
        int scrollX = rootScrollView.getScrollX(); // For HorizontalScrollView
        // DO SOMETHING WITH THE SCROLL COORDINATES
    }
});

6
この回答は正解としてマークする必要があります。hsv.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {@Override public void onScrollChanged() {Log.i(TAG,"scroll:"+hsv.getScrollX());}});onStart()では、hsvHorizontalScrollView作品です。同じことがScrollViewでも機能すると思います。
JohnnyLambada 14年

3
丁度。これが最良の答えです。Horizo​​ntalScrollViewを拡張する必要はありません。ScrollViewでテストしただけで、うまく機能します。最終的なScrollView sv =(ScrollView)findViewById(R.id.scrollViewArticle); sv.getViewTreeObserver()。addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener(){@Override public void onScrollChanged(){Log.d( "onScrollChanged Y"、String.valueOf(sv.getScrollY()));}});
Raphael C


6
回答のサンプルコードでは、メモリリークが発生しています。メソッドはでaddあり、でないためset、すべてのリスナーは明示的に削除されるまで保持されます。そのため、サンプルでリスナー実装として使用されている匿名クラスがリークします(参照しているもの、つまり外部クラスとともに)。
Brett Duncavage 2015

7
おそらくばかげた質問ですが、rootScrollViewとは何ですか?
2016

49

これは非常に役立つかもしれません。のNestedScrollView代わりに使用しますScrollView。サポートライブラリ23.1ではOnScrollChangeListenertoが導入されましたNestedScrollView。だからあなたはこのようなことをすることができます。

 myScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
        @Override
        public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
            Log.d("ScrollView","scrollX_"+scrollX+"_scrollY_"+scrollY+"_oldScrollX_"+oldScrollX+"_oldScrollY_"+oldScrollY);
            //Do something
        }
    });

2
getViewTreeObserver()で以前にリスナーを追加したかどうかを追跡するよりも間違いなく簡単です。ありがとう!
Anthony Mills

しかし、どのようにNestedScrollViewを水平スクロールビューとして使用するのでしょうか。リソースが見つかりません
GensaGames 2016年

水平スクロールを使用したい場合はどうなりますか?
Nikita Axyonov 2017年

7
@ dazed'n'confused NestedScrollViewはサポートライブラリの一部であり、そのsetOnScrollChangeListenerメソッドには最小バージョンの要件はありません。
トム

4
混同してはならないViewsetOnScrollChangeListenerAPIレベル23が必要です
アンダースUllnæss

18

これは、スクロールとスクロール終了に関する通知を処理するために私が作成した派生Horizo​​ntalScrollViewです。ユーザーがアクティブにスクロール停止したとき、およびユーザーが離した後に完全に減速したときに適切に処理します。

public class ObservableHorizontalScrollView extends HorizontalScrollView {
    public interface OnScrollListener {
        public void onScrollChanged(ObservableHorizontalScrollView scrollView, int x, int y, int oldX, int oldY);
        public void onEndScroll(ObservableHorizontalScrollView scrollView);
    }

    private boolean mIsScrolling;
    private boolean mIsTouching;
    private Runnable mScrollingRunnable;
    private OnScrollListener mOnScrollListener;

    public ObservableHorizontalScrollView(Context context) {
        this(context, null, 0);
    }

    public ObservableHorizontalScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ObservableHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int action = ev.getAction();

        if (action == MotionEvent.ACTION_MOVE) {
            mIsTouching = true;
            mIsScrolling = true;
        } else if (action == MotionEvent.ACTION_UP) {
            if (mIsTouching && !mIsScrolling) {
                if (mOnScrollListener != null) {
                    mOnScrollListener.onEndScroll(this);
                }
            }

            mIsTouching = false;
        }

        return super.onTouchEvent(ev);
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldX, int oldY) {
        super.onScrollChanged(x, y, oldX, oldY);

        if (Math.abs(oldX - x) > 0) {
            if (mScrollingRunnable != null) {
                removeCallbacks(mScrollingRunnable);
            }

            mScrollingRunnable = new Runnable() {
                public void run() {
                    if (mIsScrolling && !mIsTouching) {
                        if (mOnScrollListener != null) {
                            mOnScrollListener.onEndScroll(ObservableHorizontalScrollView.this);
                        }
                    }

                    mIsScrolling = false;
                    mScrollingRunnable = null;
                }
            };

            postDelayed(mScrollingRunnable, 200);
        }

        if (mOnScrollListener != null) {
            mOnScrollListener.onScrollChanged(this, x, y, oldX, oldY);
        }
    }

    public OnScrollListener getOnScrollListener() {
        return mOnScrollListener;
    }

    public void setOnScrollListener(OnScrollListener mOnEndScrollListener) {
        this.mOnScrollListener = mOnEndScrollListener;
    }

}

1
これはViewTreeObserverメソッドを使用するよりも優れているようです。ListViewsとScrollViewsを使用して複数のフラグメント(たとえば、スライドタブ付きの3つのフラグメント)をロードし、特定のビューのイベントを登録する必要があるアクティビティがある場合に限ります。一方、ViewTreeObserverが登録されている場合は、アクティブなビューでなくてもイベントが発生します。
Torsten Ojaperv、2015年

3
@ZaBlanc-このクラスと、ScrollViewを保持する私のアクティビティのリスナーを初期化する方法を教えてください。私はそれをうまく実装しましたが、リスナーはまだ値を返しません。
Edmond Tamas

これは実際に機能します!sdk> 23の必要はありません:)
Matan Dahan

5

ビューのスクロール位置を知りたい場合は、Viewクラスで次の拡​​張関数を使用できます。

fun View?.onScroll(callback: (x: Int, y: Int) -> Unit) {
    var oldX = 0
    var oldY = 0
    this?.viewTreeObserver?.addOnScrollChangedListener {
        if (oldX != scrollX || oldY != scrollY) {
            callback(scrollX, scrollY)
            oldX = scrollX
            oldY = scrollY
        }
    }
}

5

NestedScrollView代わりに使用できますScrollView。ただし、Kotlin Lambdaを使用している場合setOnScrollChangeListenerは、ビューでのビュー(APIレベル23)ではなくNestedScrollViewが必要かどうかはわかりません。これを修正するには、最初のパラメーターをNestedScrollViewとして指定します。

nestedScrollView.setOnScrollChangeListener { _: NestedScrollView, scrollX: Int, scrollY: Int, _: Int, _: Int ->
    Log.d("ScrollView", "Scrolled to $scrollX, $scrollY")
}

viewTreeObserverを使用するメソッドはメモリリークを引き起こし、手動で削除する必要があるため、これは受け入れられる答えになるはずです。そうしないと、複数のスクロールオブザーバが追加されます。
Ray Li

1
    // --------Start Scroll Bar Slide--------
    final HorizontalScrollView xHorizontalScrollViewHeader = (HorizontalScrollView) findViewById(R.id.HorizontalScrollViewHeader);
    final HorizontalScrollView xHorizontalScrollViewData = (HorizontalScrollView) findViewById(R.id.HorizontalScrollViewData);
    xHorizontalScrollViewData.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            int scrollX; int scrollY;
            scrollX=xHorizontalScrollViewData.getScrollX();
            scrollY=xHorizontalScrollViewData.getScrollY();
            xHorizontalScrollViewHeader.scrollTo(scrollX, scrollY);
        }
    });
    // ---------End Scroll Bar Slide---------

誰もが打者を理解できるように、コードをサポートするための説明を追加してみてください
Aniruddha Das

このコードは別の回答と非常によく似ていますね。
セルギ

1

カスタムScrollViewクラスを定義し、次のようにスクロールするときに呼び出されるインターフェイスを追加できます。

public class ScrollChangeListenerScrollView extends HorizontalScrollView {


private MyScrollListener mMyScrollListener;

public ScrollChangeListenerScrollView(Context context) {
    super(context);
}

public ScrollChangeListenerScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public ScrollChangeListenerScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}


public void setOnMyScrollListener(MyScrollListener myScrollListener){
    this.mMyScrollListener = myScrollListener;
}


@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    super.onScrollChanged(l, t, oldl, oldt);
    if(mMyScrollListener!=null){
        mMyScrollListener.onScrollChange(this,l,t,oldl,oldt);
    }

}

public interface MyScrollListener {
    void onScrollChange(View view,int scrollX,int scrollY,int oldScrollX, int oldScrollY);
}

}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.