Android : ScrollView가 스크롤을 중지 할 때 감지


84

나는 ScrollViewAndroid 에서을 사용 하고 있으며의 보이는 부분 ScrollViewScrollview. 모든 "셀"은 동일한 높이입니다. 그래서 내가하려는 ScrollView것은 스크롤 된 후 제자리에 스냅하는 것입니다 .

현재 사용자가를 터치하고 ScrollView스크롤을 시작하고 거기에서 작업을 시작했을 때 감지 하고 있지만 버그가 상당히 많습니다. 사용자가 그냥 튕겨서 스크롤 한 다음 감속 할 때도 작동해야합니다.

iPhone에는 비슷한 기능이 있으며 스크롤이 끝나면 didDecelerate원하는 코드를 할 수 있습니다 ScrollView. Android에 그런 것이 있습니까? 아니면 더 나은 방법을 찾기 위해 볼 수있는 코드가 있습니까?

Android 문서를 살펴 보았지만 그런 것을 찾을 수 없었습니다.

답변:


101

최근에 설명하신 기능을 구현해야했습니다. 내가 한 일은 onTouchEvent가 처음 트리거 될 때 getScrollY ()가 반환 한 값을 변수 newCheck에 정의 된 시간 후에 반환 된 값과 비교하여 ScrollView가 스크롤을 중지했는지 Runnable을 확인하는 것이 었습니다 .

아래 코드 (작동 솔루션)를 참조하십시오.

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
고마워요, 이와 같은 것을 위해 나이를 찾고 있습니다. 대신 HorizontalScrollView에 사용되며 (분명히) 작동합니다. 만 getScrollY는 () getScrollX ()로 대체 할 수있다
Schnodahipfe

1
여기에서 모두 시도했습니다. 이것은 작동하는 유일한 것입니다.
Mike6679

23

다음은 ScrollView에서 OnEndScroll 이벤트 버그가 누락 된 IMHO에 대한 또 다른 수정 사항입니다.

해로운 대답에서 영감을 얻었습니다 . 이 클래스를 프로젝트에 드롭하고 (자신의 것과 일치하도록 패키지 변경) 아래 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값입니다.
Phil

2
이 구현은 좋지만 시작시 스크롤 뷰가 채워지지 않으면 실패했습니다. 다음은 해결 방법입니다 (가로 스크롤 뷰의 경우 모든 x를 y로 대체하여 세로로 가져옴) : @Override protected void 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 2013-04-12

이것은 항상 작동하지 않습니다. 에뮬레이터에서와 같이 public void fling (int velocityY)가 항상 호출되는 것은 아닙니다. 스크롤 종료 임계 값은 때때로 20 픽셀 이상입니다.
Andrew Feng

9

(Horizontal) ScrollView를 서브 클래 싱하고 다음과 같이했습니다.

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

항상 마지막 onScrollChanged 이벤트의 차이 인 것처럼 보이기 때문에 SlowDownThreshold에 1의 값을 사용했습니다.

천천히 드래그 할 때 이것이 올바르게 작동하도록하려면 다음을 수행해야합니다.

@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도 처리했습니다. 그렇지 않으면 클릭시 다른 활동을 여는 경우 현재 Touching이 true로 유지됩니다.
Cynichniy Bandera

한 가지 더 수정 사항 : onScrollChanged ()에서 속도 저하가 아직 1이 아니더라도 스크롤 끝을 확인해야합니다. 다음과 같이 : boolean end = (oldx> x)? (x <= 0) : (x> = getMaxScrollAmount ()); if (Math.abs (x-oldx)> 1 &&! end) {스크롤 시작; } else {scroll end}
Cynichniy Bandera

이것은 GS3와 같은 일부 장치에서는 작동하지 않습니다. 내 GS3에서 y와 이전 y 사이의 차이는 스크롤 중간에 1이 될 수 있습니다. 그래도 Nexus 4에서 완벽하게 작동합니다. 이유를 잘 모르겠습니다.
Bryan

Samsung Galaxy Note 2 및 Asus Memo Pad 7에서도 작동하지 않습니다. 또한 이러한 장치의 스크롤 중간에 1 씩 증가하는 것을 볼 수 있습니다.
Oliver Hausler 2014

7

내 접근 방식은 onScrollChanged ()가 호출 될 때마다 변경된 타임 스탬프에 의해 스크롤 상태를 결정하는 것입니다. 스크롤링의 시작과 끝을 결정하는 것은 매우 쉽습니다. 임계 값을 변경 (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
    }

}

훌륭한 솔루션입니다. 예상대로 작동합니다.
Oliver Hausler 2014

코드 주셔서 감사합니다. 코드에서 스크롤 시작 리스너 메소드를 감지하는 방법. 내 질문 찾아보세요 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

내 솔루션은 Lin Yu Cheng의 훌륭한 솔루션의 변형이며 스크롤이 시작되고 중지 된시기도 감지합니다.

1 단계. HorizontalScrollView 및 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 단계. CustomHorizontalScrollView 클래스를 추가합니다.

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 에서이 질문을 살펴보십시오. 질문 과 정확히 같지는 않지만 .NET Framework의 스크롤 이벤트를 관리 할 수있는 방법에 대한 아이디어를 제공합니다 ScrollView.

기본적 CustomScrollView으로 확장 ScrollView하고 재정 의하여 직접 만들어야합니다 onScrollChanged(int x, int y, int oldx, int oldy). 그런 다음 .NET ScrollView과 같은 표준 대신 레이아웃 파일에서 이것을 참조해야합니다 com.mypackage.CustomScrollView.


이 onScrollChanged ()는 실제로 내가 사용하고있는 것입니다. 그래도 고마워.
user1053691

2

설명한 것과 같은 간단한 사례의 경우 사용자 지정 스크롤 뷰에서 fling 메서드를 재정 의하여 벗어날 수 있습니다. Fling 메서드는 사용자가 화면에서 손가락을 올릴 때마다 "감속"을 수행하도록 호출됩니다.

따라서해야 할 일은 다음과 같습니다.

  1. ScrollView 하위 클래스.

    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. 하위 클래스 fling 메서드 및 수퍼 클래스 구현을 호출하지 마십시오.

    @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. 사용자가 손가락을 올리기 전에 스크롤을 중지하면 Fling이 트리거되지 않습니다 (velocityY == 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 인스턴스는 해당 클래스를 Scroller에서 OvershootScroller로 2.3과 3.0 사이에서 변경했습니다. 이 모든 작은 차이점을 명심해야합니다. 어쨌든 미래에 예상치 못한 결과에 대비하십시오.


두 번째 단계 (2)에서 container.getHeight ()는 무엇입니까?
Mitul Varmora 2016

1
container는 scrollView 내부에있는 뷰입니다. scrollView는 자식을 1 개만 포함 할 수 있으므로 container를 getChildAt (0)으로 바꿀 수 있습니다.
Alexey 2011

2

여기에 몇 가지 훌륭한 답변이 있지만 ScrollView 클래스를 확장하지 않고도 스크롤이 중지 될 때 내 코드가 감지 할 수 있습니다. 모든 뷰 인스턴스는 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에서 postDelayed를 반복적이고 상호 호출하면 메모리 누수가 발생할 것이라고 추측합니다.
Oliver Hausler 2014

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 메소드를 알아 차리지 못했습니다.
Jordi Coscolla 2011

3
감사. 이 isFinished () 메서드에 어떻게 액세스합니까? ScrollView.java 파일을 살펴 보았고 mScroller는 비공개이며이 파일에 액세스 할 수있는 방법이 없습니다.
user1053691

음, 참으로. 나는 충분히 가까이 보지 않았다. 그것이 내가 먼저 시도하겠다고 말한 이유입니다 :). 에 대한 통화 추적과 같은 다른 작업을 수행 할 수 있습니다 onScrollChanged.scrollTo 또는 다른 스크롤 관련 방법. 또는 전체 ScrollView코드를 복사하여 해당 필드를 만들 수 있습니다 protected. 그래도 권장하지 않습니다.
Felix

1
리플렉션을 통해 mScroller에 액세스했습니다. 너무 작동하지 않는 isFinished ()는 스크롤 뷰가 손가락 위치에 도달 할 때마다 트리거되며 이는 거의 연속적입니다.
amik

20
이 대답은 정말 유망 해 보였지만 일종의 막 다른 골목길이므로 제거해야할까요?
spaaarky21

2

이것은 오래된 스레드이지만 더 짧은 솔루션을 추가하고 싶습니다.

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

            handler.removeCallbacksAndMessages(null)

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

당연히 1000 밀리 초의 지연이 있습니다. 필요한 경우 조정하십시오.


1

ZeroG의 답변을 약간 개선했습니다. 주로 초과 작업 호출을 취소하고 모든 것을 개인 OnTouchListener로 구현하므로 모든 스크롤 감지 코드가 한곳에 있습니다.

다음 코드를 자신의 ScrollView 구현에 붙여 넣습니다.

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

}

그런 다음 ScrollView 구현에서 :

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...

            }

스 니펫이 도움이되기를 바랍니다. :)


불행히도 ListView가 아닌 ​​ScrollView를 사용하고 있습니다. 그래도 고마워.
user1053691

1
여보세요? ScrollView가 ListView가 아닙니다.
Kevin Parker
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.