ScrollView için onScrollListener'a sahip olabilir miyim?


140

HorizontalScrollViewBir düzen içinde bir kullanıyorum ve kullanıcının kaydırma başlangıç ​​ve bitiş noktasına ulaşmış tanımlamak gerekir.

Çünkü ListViewben denedim onScrollListenerve kaydırma başlangıç ​​ve bitiş noktasını bulmak mümkündür.

Ben de aynısını yapmaya çalıştım Scrollviewama bu mümkün görünmüyor. İhtiyacım olanı elde etmenin başka olası yolları var mı?


3
Bu mümkün. Kullanıcı2695685'in cevabına bakın. Kısacası aşağıdaki onStarthile yapacaktır: hsv.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {@Override public void onScrollChanged() {Log.i(TAG,"scroll:"+hsv.getScrollX());}});onStart () nerede hsvbir eserdir HorizontalScrollView.
JohnnyLambada

yararlı cevap herkes kabul .. başka kendi cevap göndermek ..
Ranjith Kumar

12
Android'de ScrollView ile bir kaydırma olayını tespit etmek neden bu kadar zor? Bu fındık imo.
çalıştı

Yanıtlar:


389

View çağrılarının her örneği getViewTreeObserver(). Şimdi bir örneğini tutarken , yöntemi kullanarak bir örneğini ViewTreeObserverekleyebilirsiniz .OnScrollChangedListener()addOnScrollChangedListener()

Bu sınıf hakkında daha fazla bilgiyi burada görebilirsiniz .

Her kaydırma olayından haberdar olmanızı sağlar - ancak koordinatlar olmadan. Bunları dinleyicinin içinden getScrollY()ya getScrollX()da içinden kullanarak alabilirsiniz .

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
Bu cevap doğru olarak işaretlenmelidir. hsv.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {@Override public void onScrollChanged() {Log.i(TAG,"scroll:"+hsv.getScrollX());}});onStart içinde nerede () hsvbir olduğunu HorizontalScrollViewçalışır. Aynı bir ScrollView için de çalışacağından şüpheleniyorum.
JohnnyLambada

3
kesinlikle. bu en iyi cevap. HorizontalScrollView öğesini genişletmeye gerek yoktur. Sadece bir ScrollView ile test edildi, harika çalışıyor: son ScrollView sv = (ScrollView) findViewById (R.id.scrollViewArticle); sv.getViewTreeObserver (). addOnScrollChangedListener (yeni ViewTreeObserver.OnScrollChangedListener () {@OverScrollChanged () {Log.d ("onScrollChanged Y", String.valueOf (sv.getScrollY)}););)
Raphael C


7
Yanıttaki örnek kodda bellek sızıntısı var. Yöntem olduğundan addve olmadığından set, tüm dinleyiciler açıkça kaldırılana kadar korunur. Böylece, örnekte bir dinleyici uygulaması olarak kullanılan anonim sınıf sızıntı yapacaktır (referans aldığı herhangi bir şeyle, yani dış sınıfla).
Brett Duncavage

7
Muhtemelen aptalca bir soru, ama rootScrollView nedir?
Iqbal

49

Bu çok faydalı olabilir. Yerine NestedScrollViewkullanın ScrollView. Destek Kitaplığı 23.1 bir tanıtılan OnScrollChangeListeneriçin NestedScrollView. Böylece böyle bir şey yapabilirsiniz.

 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 () ile dinleyiciyi daha önce ekleyip eklemediğinizi takip etmekten kesinlikle daha kolay. Teşekkürler!
Anthony Mills

Ancak NestedScrollView'ı yatay kaydırma görünümü olarak nasıl kullanırsınız? Herhangi bir kaynak bulunamıyor
GensaGames

Yatay kaydırma kullanmak istersem ne olur?
Nikita Axyonov

7
@ dazed'n'confused NestedScrollView, destek kitaplığının bir parçasıdır, setOnScrollChangeListeneryönteminin minimum sürüm gereksinimi yoktur.
Tom

4
API seviyesi 23 gerektiren View's ile karıştırılmamalıdırsetOnScrollChangeListener
Anders Ullnæss

18

Aşağıda, kaydırma ve kaydırma sonlandırmasıyla ilgili bildirimleri işlemek için yazılan türetilmiş bir HorizontalScrollView I yazılmıştır. Bir kullanıcı etkin olarak kaydırmayı durdurduğunda ve bir kullanıcı izin verdikten sonra tamamen yavaşladığında düzgün bir şekilde işler :

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
Bu, ViewTreeObserver yöntemini kullanmaktan daha iyi gibi görünüyor. ListViews ve ScrollViews ile birden fazla parçanızın (örneğin, kayan sekmeli 3 parçanın) yüklü olduğu bir etkinliğiniz olduğunda ve olayları belirli bir görünüm için kaydetmeniz gerektiğinde. Oysa ViewTreeObserver kayıtlıysa, etkin görünüm olmasa bile olayları tetikler.
Torsten Ojaperv

3
@ZaBlanc - Lütfen bu sınıfı ve ScrollView tutan Etkinliğimdeki dinleyicileri nasıl başlatacağımı söyleyebilir misiniz? Sadece iyi uyguladım, ancak dinleyiciler henüz herhangi bir değer döndürmeyecek.
Edmond Tamas

Bu gerçekten işe yarıyor! ve sdk gerek> 23 bunun için :)
Matan Dahan

5

Bir görünümün kaydırma konumunu bilmek istiyorsanız, View sınıfında aşağıdaki uzantı işlevini kullanabilirsiniz:

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

Bunun NestedScrollViewyerine kullanabilirsiniz ScrollView. Ancak, bir Kotlin Lambda kullanırken setOnScrollChangeListener, View (API seviye 23) yerine NestedScrollView's istediğinizi bilemez . Bunu ilk parametreyi NestedScrollView olarak belirterek düzeltebilirsiniz.

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

Bir viewTreeObserver kullanan yöntem bellek sızıntılarına neden olduğundan ve manuel olarak kaldırılması gerektiğinden, birden fazla kaydırma gözlemcisi ekleneceğinden bu kabul edilen yanıt olmalıdır.
Ray Li

1

özel bir ScrollView sınıfı tanımlayabilir ve aşağıdaki gibi kaydırırken çağrılacak bir arabirim ekleyebilirsiniz:

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);
}

}

0
    // --------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---------

lütfen herkesin
meyilliğini

Bu kod başka bir cevaba çok benziyor , değil mi?
Sergii
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.