Android: जब स्क्रॉल स्क्रॉल बंद हो जाता है तो पता लगाएं


84

मैं ScrollViewएंड्रॉइड में उपयोग कर रहा हूं और जहां दृश्यमान भाग ScrollViewएक ही आकार का है, जो कि एंड्रॉइड के अंदर की कोशिकाओं में से एक है Scrollview। प्रत्येक "सेल" समान ऊंचाई है। इसलिए जो मैं करने की कोशिश कर रहा हूं ScrollViewवह स्क्रॉल किए जाने के बाद स्थिति में है।

वर्तमान में मैं यह पता लगा रहा हूं कि जब उपयोगकर्ता ने छुआ है ScrollViewऔर जब वे स्क्रॉल करना शुरू कर चुके हैं और इसे वहां से काम कर रहे हैं, लेकिन यह काफी छोटी है। यह भी काम करने की जरूरत है जब उपयोगकर्ता बस इसे चोंचता है और इसे स्क्रॉल करता है और फिर डीलेरेट करता है।

IPhone पर एक ऐसा फंक्शन होता है, जो कुछ ऐसा होता है didDecelerateऔर वहां मैं कोई भी कोड कर सकता हूं, जिसे मैंने ScrollViewस्क्रॉल किया है। क्या Android के साथ ऐसा है? या वहाँ कुछ कोड मैं यह करने का एक बेहतर तरीका जानने के लिए देख सकता है?

मैंने एंड्रॉइड डॉक्स पर देखा है और ऐसा कुछ भी नहीं मिला।

जवाबों:


101

मुझे हाल ही में आपके द्वारा वर्णित फ़ंक्शन को लागू करना था। मैंने क्या किया था कि एक रनवेबल चेक आउट हो सकता है अगर स्क्रॉलव्यू ने getScrollY () द्वारा लौटाए गए मान की तुलना करके स्क्रॉल करना बंद कर दिया हो, जब onTouchEvent को पहली बार वेरिएबल चेकचेक द्वारा परिभाषित समय के बाद लौटाए गए मान के साथ ट्रिगर किया गया हो ।

नीचे दिया गया कोड देखें (कार्य समाधान):

public class MyScrollView extends ScrollView{

private Runnable scrollerTask;
private int initialPosition;

private int newCheck = 100;
private static final String TAG = "MyScrollView";

public interface OnScrollStoppedListener{
    void onScrollStopped();
}

private OnScrollStoppedListener onScrollStoppedListener;

public MyScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);

    scrollerTask = new Runnable() {

        public void run() {

            int newPosition = getScrollY();
            if(initialPosition - newPosition == 0){//has stopped

                if(onScrollStoppedListener!=null){

                    onScrollStoppedListener.onScrollStopped();
                }
            }else{
                initialPosition = getScrollY();
                MyScrollView.this.postDelayed(scrollerTask, newCheck);
            }
        }
    };
}

public void setOnScrollStoppedListener(MyScrollView.OnScrollStoppedListener listener){
    onScrollStoppedListener = listener;
}

public void startScrollerTask(){

    initialPosition = getScrollY();
    MyScrollView.this.postDelayed(scrollerTask, newCheck);
}

}

फिर मेरे पास है:

scroll.setOnTouchListener(new OnTouchListener() {

        public boolean onTouch(View v, MotionEvent event) {

            if (event.getAction() == MotionEvent.ACTION_UP) {

                scroll.startScrollerTask();
            }

            return false;
        }
});
scroll.setOnScrollStoppedListener(new OnScrollStoppedListener() {

        public void onScrollStopped() {

            Log.i(TAG, "stopped");

        }
});

BTW मैंने अपने ऐप में ऐसा करने के लिए अन्य उत्तरों से कुछ विचारों का उपयोग किया। उम्मीद है की यह मदद करेगा। आप किसी भी समय प्रश्न पूछने के स्वतंत्र हैं। चीयर्स।


11
धन्यवाद, इस तरह से कुछ के लिए उम्र की तलाश कर रहे हैं। इसके बजाय क्षैतिज क्षैतिज नियंत्रण रेखा के लिए उपयोग किया जाता है, जो (जाहिर है) भी काम करता है। केवल getScrollY () को
getScrollX

1
यहां सबने कोशिश की। यह केवल एक ही है जो काम करता है।
माइक ६६ Mike

23

यहाँ पर अभी तक एक और फिक्स है, IMHO, अनुपलब्ध OnEndScroll घटना बग स्क्रॉल में।

यह हैमोनियस उत्तर से प्रेरित है । बस अपनी परियोजना में इस वर्ग को छोड़ें (अपने से मेल खाने के लिए पैकेज बदलें) और नीचे दिए गए xml का उपयोग करें

package com.thecrag.components.ui;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;

public class ResponsiveScrollView extends ScrollView {

    public interface OnEndScrollListener {
        public void onEndScroll();
    }

    private boolean mIsFling;
    private OnEndScrollListener mOnEndScrollListener;

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

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

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

    @Override
    public void fling(int velocityY) {
        super.fling(velocityY);
        mIsFling = true;
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldX, int oldY) {
        super.onScrollChanged(x, y, oldX, oldY);
        if (mIsFling) {
            if (Math.abs(y - oldY) < 2 || y >= getMeasuredHeight() || y == 0) {
                if (mOnEndScrollListener != null) {
                    mOnEndScrollListener.onEndScroll();
                }
                mIsFling = false;
            }
        }
    }

    public OnEndScrollListener getOnEndScrollListener() {
        return mOnEndScrollListener;
    }

    public void setOnEndScrollListener(OnEndScrollListener mOnEndScrollListener) {
        this.mOnEndScrollListener = mOnEndScrollListener;
    }

}

अपनी परियोजना से मिलान करने के लिए फिर से पैकेज का नाम बदलना

<com.thecrag.components.ui.ResponsiveScrollView
        android:id="@+id/welcome_scroller"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/welcome_scroll_command_help_container"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/welcome_header_text_thecrag"
        android:layout_margin="6dp">
    ....
</com.thecrag.components.ui.ResponsiveScrollView>

2
+1 अच्छा, सरल उत्तर। मैं अंतर मान बदलने 2के लिए 0.5fमूल को प्रतिबिंबित करने ScrollViewके MAX_SCROLL_FACTORमूल्य।
फिल

2
यह कार्यान्वयन अच्छा है, लेकिन यह तब विफल हुआ जब स्क्रॉल दृश्य प्रारंभ में भरा नहीं गया था। यहाँ एक वर्कअराउंड है (क्षैतिज स्क्रॉल दृश्य के लिए, इसलिए वर्टिकल को प्राप्त करने के लिए सभी x को y से बदलें): @Override संरक्षित शून्य onScrollChanged (int x, int y, int oldX, int oldY) {super .onScrollChanged (x, y , oldX, oldY); if (Math.abs (x - oldX) <SCROLL_FINISHED_THRESHOLD && x! = lastStopX || x> = getMeasuredWidth () = x == 0) {lastStopX = x? if (mOnEndScrollListener! = null) {mOnEndScrollListener.onScrollEnded (); }}}
Snicolas

यह हमेशा काम नहीं करता है। एमुलेटर में, सार्वजनिक शून्य प्रवाह (इंट वेलोसिटी) को हमेशा नहीं कहा जाता है। स्क्रॉल एंड थ्रेशोल्ड कभी-कभी 20 px से अधिक होता है।
एंड्रयू फेंग

9

मैंने (क्षैतिज) स्क्रॉलव्यू को उप-वर्गित किया और कुछ इस तरह किया:

@Override
protected void onScrollChanged(int x, int y, int oldX, int oldY) {
    if (Math.abs(x - oldX) > SlowDownThreshold) {  
        currentlyScrolling = true;
    } else {
        currentlyScrolling = false;
        if (!currentlyTouching) {
            //scrolling stopped...handle here
        }
    }
    super.onScrollChanged(x, y, oldX, oldY);
}

मैंने SlowDownThreshold के लिए 1 के मान का उपयोग किया क्योंकि यह हमेशा अंतिम onScrollChanged इवेंट का अंतर प्रतीत होता है।

धीरे-धीरे खींचते समय इसे सही ढंग से व्यवहार करने के लिए, मुझे यह करना पड़ा:

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            currentlyTouching = true;
    }
    return super.onInterceptTouchEvent(event);
}

@Override
public boolean onTouch(View view, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            currentlyTouching = false;
            if (!currentlyScrolling) {
                //I handle the release from a drag here
                return true;
            }
    }
    return false;
}

अच्छा जवाब। एक ही जोड़। OnInterceptTouchEvent () में आपके पास MotionEvent.ACTION_UP और MotionEvent.ACTION_CANCEL भी हैं, अन्यथा वर्तमान में यह सही रहेगा कि आप क्लिक पर एक और गतिविधि खोलें।
सिंथी बांदेरा

एक और तय: onScrollChanged () में आपको स्क्रॉल के अंत की जांच करनी होगी, भले ही मंदी अभी भी नहीं है। 1. इस तरह: बूलियन अंत = (oldx> x)? (x <= 0): (x> = getMaxScrollAmount ()); अगर (Math.abs (x - oldx)> 1 &&! अंत) {स्क्रॉल प्रारंभ; } और {स्क्रॉल एंड}
Cynichniy Bandera

यह कुछ उपकरणों यानी GS3 पर काम नहीं करता है। मेरे जीएस 3 पर, स्क्रॉल के बीच में y और पुरानी y के बीच का अंतर 1 हो सकता है। यह पूरी तरह से मेरे Nexus 4 पर काम करता है। मुझे यकीन नहीं है कि क्यों।
ब्रायन

सैमसंग गैलेक्सी नोट 2 और आसुस मेमो पैड 7 पर भी काम नहीं कर रहा है। मुझे इन उपकरणों पर स्क्रॉल के बीच में 1 की वृद्धि भी दिखाई देती है।
ओलिवर हॉसलर

7

मेरे दृष्टिकोण को निर्धारित किया जाता है कि एक टाइमस्टैम्प द्वारा हर बार ऑनस्कॉलचेंज () कहा जाता है। यह निर्धारित करना बहुत आसान है कि स्क्रॉलिंग की शुरुआत और अंत कब होता है। संवेदनशीलता को ठीक करने के लिए आप थ्रेशोल्ड (I 100ms का उपयोग) भी बदल सकते हैं।

public class CustomScrollView extends ScrollView {
    private long lastScrollUpdate = -1;

    private class ScrollStateHandler implements Runnable {

        @Override
        public void run() {
            long currentTime = System.currentTimeMillis();
            if ((currentTime - lastScrollUpdate) > 100) {
                lastScrollUpdate = -1;
                onScrollEnd();
            } else {
                postDelayed(this, 100);
            }
        }
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (lastScrollUpdate == -1) {
            onScrollStart();
            postDelayed(new ScrollStateHandler(), 100);
        }

        lastScrollUpdate = System.currentTimeMillis();
    }

    private void onScrollStart() {
        // do something
    }

    private void onScrollEnd() {
        // do something
    }

}

महान समाधान। के रूप में काम करता है।
ओलिवर हॉसलर

आपके कोड के लिए धन्यवाद। अपने कोड से स्क्रॉल स्टार्ट श्रोता विधि का पता कैसे लगाएं। कृपया मेरे प्रश्न को देखें stackoverflow.com/questions/27864700/…
MAMurali

6

यहाँ अभी तक एक और समाधान है, मेरी राय में काफी सरल और साफ है, स्वाभाविक रूप से उपरोक्त उत्तरों से प्रेरित है। मूल रूप से एक बार देरी (50ms) के बाद getScrollY () अभी भी बदल रहा है, तो उपयोगकर्ता एक बार इशारे की जांच समाप्त कर देता है।

public class ScrollViewWithOnStopListener extends ScrollView {

    OnScrollStopListener listener;

    public interface OnScrollStopListener {
        void onScrollStopped(int y);
    }

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

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

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_UP:
                checkIfScrollStopped();
        }

        return super.onTouchEvent(ev);
    }

    int initialY = 0;

    private void checkIfScrollStopped() {
        initialY = getScrollY();
        this.postDelayed(new Runnable() {
            @Override
            public void run() {
                int updatedY = getScrollY();
                if (updatedY == initialY) {
                    //we've stopped
                    if (listener != null) {
                        listener.onScrollStopped(getScrollY());
                    }
                } else {
                    initialY = updatedY;
                    checkIfScrollStopped();
                }
            }
        }, 50);
    }

    public void setOnScrollStoppedListener(OnScrollStopListener yListener) {
        listener = yListener;
    }
}

5

इस प्रश्न के लिए मेरा दृष्टिकोण निम्नलिखित 2 "घटनाओं" की जांच के लिए एक टाइमर का उपयोग करना है।

1) onScrollChanged () को बुलाया जाना बंद हो गया

2) उपयोगकर्ता की उंगली स्क्रोलव्यू से ऊपर उठती है

public class CustomScrollView extends HorizontalScrollView {

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

Timer ntimer = new Timer();
MotionEvent event;

@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) 
{
    checkAgain();
    super.onScrollChanged(l, t, oldl, oldt);
}

public void checkAgain(){
    try{
        ntimer.cancel();
        ntimer.purge();
    }
    catch(Exception e){}
    ntimer = new Timer();
    ntimer.schedule(new TimerTask() {

        @Override
        public void run() {

            if(event.getAction() == MotionEvent.ACTION_UP){
                // ScrollView Stopped Scrolling and Finger is not on the ScrollView
            }
            else{
                // ScrollView Stopped Scrolling But Finger is still on the ScrollView
                checkAgain();
            }
        }
    },100);

}

@Override
public boolean onTouchEvent(MotionEvent event) {
    this.event = event; 
    return super.onTouchEvent(event);
    }
}

3

मेरा समाधान लिन यू चेंग के महान समाधान का रूपांतर है और यह भी पता चलता है कि स्क्रॉलिंग कब शुरू और बंद हुई है।

चरण 1. एक क्षैतिज दृश्य को परिभाषित करें और OnScrollChangedListener:

CustomHorizontalScrollView scrollView = (CustomHorizontalScrollView) findViewById(R.id.horizontalScrollView);

horizontalScrollListener = new CustomHorizontalScrollView.OnScrollChangedListener() {
    @Override
    public void onScrollStart() {
        // Scrolling has started. Insert your code here...
    }

    @Override
    public void onScrollEnd() {
         // Scrolling has stopped. Insert your code here...
    }
};

scrollView.setOnScrollChangedListener(horizontalScrollListener);

चरण 2।

public class CustomHorizontalScrollView extends HorizontalScrollView {
    public interface OnScrollChangedListener {
        // Developer must implement these methods.
        void onScrollStart();
        void onScrollEnd();
    }

    private long lastScrollUpdate = -1;
    private int scrollTaskInterval = 100;
    private Runnable mScrollingRunnable;
    public OnScrollChangedListener mOnScrollListener;

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

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

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

    private void init(Context context) {
        // Check for scrolling every scrollTaskInterval milliseconds
        mScrollingRunnable = new Runnable() {
            public void run() {
                if ((System.currentTimeMillis() - lastScrollUpdate) > scrollTaskInterval) {
                    // Scrolling has stopped.
                    lastScrollUpdate = -1;
                    //CustomHorizontalScrollView.this.onScrollEnd();
                    mOnScrollListener.onScrollEnd();
                } else {
                    // Still scrolling - Check again in scrollTaskInterval milliseconds...
                    postDelayed(this, scrollTaskInterval);
                }
            }
        };
    }

    public void setOnScrollChangedListener(OnScrollChangedListener onScrollChangedListener) {
        this.mOnScrollListener = onScrollChangedListener;
    }

    public void setScrollTaskInterval(int scrollTaskInterval) {
        this.scrollTaskInterval = scrollTaskInterval;
    }

    //void onScrollStart() {
    //    System.out.println("Scroll started...");
    //}

    //void onScrollEnd() {
    //    System.out.println("Scroll ended...");
    //}

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (mOnScrollListener != null) {
            if (lastScrollUpdate == -1) {
                //CustomHorizontalScrollView.this.onScrollStart();
                mOnScrollListener.onScrollStart();
                postDelayed(mScrollingRunnable, scrollTaskInterval);
            }

            lastScrollUpdate = System.currentTimeMillis();
        }
    }
}

2

StackOverflow पर यहाँ इस प्रश्न पर एक नज़र डालने की कोशिश करें - यह बिल्कुल आपके प्रश्न के समान नहीं है, लेकिन यह इस पर एक विचार देता है कि आप किस तरह से स्क्रॉल इवेंट का प्रबंधन कर सकते हैं ScrollView

मूल रूप से आपको CustomScrollViewविस्तार ScrollViewऔर ओवरराइड करके अपना खुद का निर्माण करना होगा onScrollChanged(int x, int y, int oldx, int oldy)। तो फिर तुम मानक के बजाय अपने लेआउट फ़ाइल में इस संदर्भ की जरूरत है ScrollViewकी तरह com.mypackage.CustomScrollView


यह onScrollChanged () वास्तव में है जो मैं मिनट में उपयोग कर रहा हूं। हालांकि धन्यवाद।
user1053691

2

आपके द्वारा वर्णित एक साधारण मामले के लिए, आप शायद अपने कस्टम स्क्रॉल दृश्य में ओवरराइडिंग फ़्लिंग विधि से दूर हो सकते हैं। हर बार जब उपयोगकर्ता स्क्रीन से अपनी उंगली उठाता है तो फ़्लिंग विधि को "मंदी" करने के लिए बुलाया जाता है।

तो आपको क्या करना चाहिए ऐसा कुछ है:

  1. उपवर्ग स्क्रॉल।

    public class MyScrollView extends ScrollView { 
    
        private Scroller scroller;  
        private Runnable scrollerTask; 
    
        //...
    
        public MyScrollView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            scroller = new Scroller(getContext()); //or OverScroller for 3.0+
            scrollerTask = new Runnable() {
                @Override
                public void run() {
                    scroller.computeScrollOffset();
                    scrollTo(0, scroller.getCurrY());
    
                    if (!scroller.isFinished()) {
                        MyScrollView.this.post(this);
                    } else {
                        //deceleration ends here, do your code
                    }
                }
            };
            //...
        }
    }
    
  2. उपवर्ग फ्लिंग विधि और सुपरक्लास कार्यान्वयन को कॉल न करें।

    @Override  
    public void fling(int velocityY) {  
        scroller.fling(getScrollX(), getScrollY(), 0, velocityY, 0, 0, 0, container.getHeight());
        post(scrollerTask);  
    
        //add any extra functions you need from android source code:
        //show scroll bars
        //change focus
        //etc.
    }
    
  3. यदि उपयोगकर्ता अपनी उंगली उठाने से पहले स्क्रॉल करना बंद कर देता है तो फ्लिंग ट्रिगर नहीं करेगा (वेग == 0)। मामले में आप इस तरह की घटनाओं को रोकना चाहते हैं, onTouchEvent को ओवरराइड करें।

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean eventConsumed = super.onTouchEvent(ev);
        if (eventConsumed && ev.getAction() == MotionEvent.ACTION_UP) {
            if (scroller.isFinished()) {
                //do your code
            }
        }
        return eventConsumed;
    }
    

नोट हालांकि यह काम करता है, ओवरराइडिंग फ़्लिंग विधि एक बुरा विचार हो सकता है। यह सार्वजनिक है, लेकिन इसके बमुश्किल उपवर्ग के लिए डिज़ाइन किया गया है। अभी यह 3 चीजें करता है - यह निजी mScroller के लिए फ़्लिंग शुरू करता है, संभव फ़ोकस परिवर्तन को हैंडल करता है और स्क्रॉल बार दिखाता है। यह भविष्य के Android रिलीज़ में बदल सकता है। उदाहरण के लिए, निजी mScroller के उदाहरण ने अपनी कक्षा को 2.3 और 3.0 के बीच Scroller से OvershootScroller में बदल दिया। आपको इन सभी छोटे अंतरों को ध्यान में रखना होगा। किसी भी मामले में, भविष्य में अप्रत्याशित परिणामों के लिए तैयार रहें।


दूसरा चरण (2) में कंटेनर.गेट हाइट () क्या है?
मितुल वर्मोरा

1
कंटेनर वह दृश्य है जो स्क्रॉलव्यू के अंदर है। चूंकि स्क्रॉलव्यू में केवल 1 बच्चा हो सकता है, आप कंटेनर को getChildAt (0) से बदल सकते हैं।
अलेक्सी

2

यहाँ कुछ शानदार उत्तर हैं, लेकिन स्क्रॉल कोड को विस्तारित किए बिना स्क्रॉल बंद होने पर मेरा कोड पता लगा सकता है। हर दृश्य का उदाहरण getViewTreeObserver () कह सकते हैं। जब ViewTreeObserver के इस उदाहरण को पकड़े हुए आप फ़ंक्शन addOnScrollChangedListener () का उपयोग करके OnScrollChangedListener जोड़ सकते हैं।

निम्नलिखित घोषित करें:

private ScrollView scrollListener;
private volatile long milesec;

private Handler scrollStopDetector;
private Thread scrollcalled = new Thread() {

    @Override
    public void run() { 
        if (System.currentTimeMillis() - milesec > 200) {
            //scroll stopped - put your code here
        }
    }
}; 

और अपने onCreate (या किसी अन्य जगह) में जोड़ें:

    scrollListener = (ScrollView) findViewById(R.id.scroll);

    scrollListener.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {

        @Override
        public void onScrollChanged() {
            milesec = System.currentTimeMillis();
            scrollStopDetector.postDelayed(scrollcalled, 200);
        }
    });

आप इस चेक के बीच अधिक समय या धीमा समय लेना चाहते हैं, लेकिन जब इस सूची को स्क्रॉल करना वास्तव में तेज़ हो जाता है तो यह बहुत तेज़ी से काम करेगा।


मैंने इस मामले में प्रयास नहीं किया है, लेकिन अपने अनुभव से मैं अनुमान लगाऊंगा कि onScrollChanged से पोस्टडेलिड की पुनरावृत्ति और पारस्परिक कॉल मेमोरी लीक का कारण बनेगी।
ओलिवर हॉसलर

2

यहाँ मेरा समाधान है जिसमें स्क्रॉल ट्रैकिंग और स्क्रॉल एंडिंग शामिल हैं:

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

}

2

मुझे लगता है कि यह अतीत में आया है। AFAIK, आप आसानी से पता नहीं लगा सकते हैं । मेरा सुझाव यह है कि आप एक नज़र डालें ScrollView.java(यह है कि हम एंड्रॉइड लैंड में चीजें कैसे करते हैं :)) और यह पता लगाएं कि आप जिस कार्यक्षमता की तलाश कर रहे हैं उसे प्रदान करने के लिए आप क्लास को कैसे बढ़ा सकते हैं। यह वही है जो मैं पहले कोशिश करूंगा:

 @Override
 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
     if (mScroller.isFinished()) {
         // do something, for example call a listener
     }
 }

अच्छा मैं isFinished विधि पर ध्यान नहीं दिया!
जोर्डी कोस्कुल्ला

3
धन्यवाद। मैं इसे कैसे पूरा करूँ? मैंने स्क्रॉलव्यू.जावा फाइल पर एक नज़र डाली और mScroller निजी है और मैं इसे एक्सेस करने का कोई तरीका नहीं बता सकता।
user1053691

हम्म, वास्तव में। मैं काफी करीब नहीं लग रहा था। इसलिए मैंने कहा कि मैं कोशिश करूंगा कि पहले :)। आप अन्य बातों के कर सकता है, ट्रैक करने के लिए कॉल की तरह onScrollChanged, scrollToया किसी भी अन्य पुस्तक से संबंधित विधि। वैकल्पिक रूप से, आप बस पूरे ScrollViewकोड की प्रतिलिपि बना सकते हैं और उस फ़ील्ड को बना सकते हैं protected। मैं यह सलाह नहीं दूंगा, हालांकि।
फेलिक्स

1
प्रतिबिंब के माध्यम से पहुँचा mScroller। यह भी काम नहीं करता है, isFinished () हर बार ट्रिगर होता है स्क्रॉलव्यू आपकी उंगली की स्थिति तक पहुंचता है, जो लगभग लगातार होता है। जब उपयोगकर्ता अपनी उंगली को छोड़ता है तो ट्रोल स्टॉप ईवेंट को आग लगनी चाहिए और स्क्रोलर स्क्रॉल करना बंद कर देता है।
आमिक

20
यह उत्तर वास्तव में आशाजनक लग रहा था लेकिन चूंकि यह मृत हो गया था, शायद इसे हटा दिया जाना चाहिए?
स्पाकार्की

2

यह एक पुराना धागा है, लेकिन मैं इसके साथ आया एक छोटा समाधान जोड़ना चाहूंगा:

 buttonsScrollView.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->

            handler.removeCallbacksAndMessages(null)

            handler.postDelayed({
                  //YOUR CODE TO BE EXECUTED HERE
                },1000)
        }

स्वाभाविक रूप से 1000 मिलीसेकेंड की देरी है। अगर आपको ज़रूरत है तो उसे समायोजित करें।


1

मैंने जीरो जी के उत्तर में कुछ सुधार किए हैं। मुख्य रूप से अतिरिक्त कार्य कॉल को रद्द करना और पूरी बात को एक निजी OnTouchListener के रूप में लागू करना है, इसलिए सभी स्क्रॉल डिटेक्शन कोड एक ही स्थान पर होंगे।

निम्नलिखित कोड को अपने स्क्रॉल दृश्य कार्यान्वयन में पेस्ट करें:

private class ScrollFinishHandler implements OnTouchListener
{
        private static final int SCROLL_TASK_INTERVAL = 100;

        private Runnable    mScrollerTask;
        private int         mInitialPosition = 0;

        public ScrollFinishHandler()
        {
            mScrollerTask = new Runnable() {

                public void run() {

                    int newPosition = getScrollY();
                    if(mInitialPosition - newPosition == 0)
                    {//has stopped

                       onScrollStopped(); // Implement this on your main ScrollView class
                    }else{
                        mInitialPosition = getScrollY();
                        ExpandingLinearLayout.this.postDelayed(mScrollerTask, SCROLL_TASK_INTERVAL);
                    }
                }
            };
        }

        @Override
        public boolean onTouch(View v, MotionEvent event) 
        {
            if (event.getAction() == MotionEvent.ACTION_UP) 
            {

                startScrollerTask();
            }
            else
            {
                stopScrollerTask();
            }

            return false;
        }

}

और फिर अपने स्क्रॉल दृश्य कार्यान्वयन में:

setOnTouchListener( new ScrollFinishHandler() );

-1
        this.getListView().setOnScrollListener(new OnScrollListener(){
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {}

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
                     if( firstVisibleItem + visibleItemCount >= totalItemCount ) 
                              // Last item is shown...

            }

आशा है कि स्निपेट मदद :)


दुर्भाग्य से मैं एक स्क्रॉल दृश्य का उपयोग कर रहा हूं, सूची दृश्य का नहीं। हालांकि धन्यवाद।
user1053691

1
नमस्कार? स्क्रॉल दृश्य सूची दृश्य नहीं।
केविन पार्कर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.