ฉันมี onScrollListener สำหรับ ScrollView ได้หรือไม่


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 () ซึ่งhsvเป็นHorizontalScrollViewงาน
JohnnyLambada

ยอมรับคำตอบที่เป็นประโยชน์กับทุกคน .. ถ้าไม่โพสต์คำตอบของคุณเอง ..
Ranjith Kumar

12
เหตุใดการตรวจจับเหตุการณ์การเลื่อนด้วย ScrollView จึงยากใน Android นี่คือถั่ว imo
ทำงาน

คำตอบ:


389

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 () ซึ่งhsvเป็นHorizontalScrollViewงาน ฉันสงสัยว่าจะใช้งาน ScrollView ได้เช่นกัน
JohnnyLambada

3
อย่างแน่นอน นี่คือคำตอบที่ดีที่สุด ไม่จำเป็นต้องขยาย HorizontalScrollView เพิ่งทดสอบกับ ScrollView ใช้งานได้ดี: ขั้นสุดท้าย ScrollView sv = (ScrollView) findViewById (R.id.scrollViewArticle); sv.getViewTreeObserver (). addOnScrollChangedListener (ใหม่ ViewTreeObserverOnScrollChangedListener () {@ โมฆะประชาชนสาธารณะโมฆะ onScrollChanged () {Log.d ("onScrollChanged Y", String.valueOf (sv.getScrollY ()
Raphael C

5
คุณควรตรวจสอบViewTreeObserver.isAlive ()
M.Salomaa

7
โค้ดตัวอย่างในคำตอบแนะนำหน่วยความจำรั่ว ตั้งแต่วิธีการเป็นaddและไม่ใช่setผู้ฟังทั้งหมดจะถูกเก็บไว้จนกว่าจะลบออกอย่างชัดเจน ดังนั้นคลาสนิรนามที่ใช้เป็นการใช้งานฟังในตัวอย่างจะรั่วไหล (พร้อมกับสิ่งที่อ้างอิงคือคลาสภายนอก)
Brett Duncavage

7
อาจเป็นคำถามที่โง่ แต่ rootScrollView คืออะไร
อิกบัล

49

สิ่งนี้อาจมีประโยชน์มาก ใช้แทนNestedScrollView ScrollViewห้องสมุดสนับสนุน 23.1 แนะนำOnScrollChangeListenerให้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 เป็นมุมมองเลื่อนแนวนอน? Cannt ค้นหาทรัพยากรใด ๆ
GensaGames

ถ้าฉันต้องการใช้การเลื่อนในแนวนอน
Nikita Axyonov

7
@ dazed'n'confused NestedScrollViewเป็นส่วนหนึ่งของไลบรารีการสนับสนุนsetOnScrollChangeListenerวิธีการไม่มีข้อกำหนดรุ่นขั้นต่ำ
Tom

4
เพื่อไม่ให้สับสนกับView's setOnScrollChangeListenerซึ่งต้องใช้ระดับ API 23
Anders Ullnæss

18

นี่คือ HorizontalScrollView ที่ได้รับมาฉันเขียนเพื่อจัดการการแจ้งเตือนเกี่ยวกับการเลื่อนและการเลื่อนสิ้นสุด มันจัดการอย่างถูกต้องเมื่อผู้ใช้หยุดการเลื่อนอย่างแข็งขันและเมื่อมันชะลอตัวลงอย่างเต็มที่หลังจากผู้ใช้ปล่อย:

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 เพียงเพราะเมื่อคุณมีกิจกรรมที่คุณโหลดหลายแฟรกเมนต์ (เช่น 3 แฟรกเมนต์ที่มีแท็บเลื่อน) พร้อมกับ ListViews และ ScrollViews และคุณต้องลงทะเบียนกิจกรรมสำหรับมุมมองเฉพาะ โดยที่ถ้า ViewTreeObserver ลงทะเบียนแล้วมันจะเริ่มการทำงานของเหตุการณ์แม้ว่าจะไม่ได้เปิดใช้งานมุมมอง
Torsten Ojaperv

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 แลมบ์ดาคุณจะไม่ทราบว่าคุณต้องการ NestedScrollView setOnScrollChangeListenerแทนที่จะเป็นมุมมอง (ซึ่งเป็นระดับ API 23) คุณสามารถแก้ไขได้โดยระบุพารามิเตอร์แรกเป็น NestedScrollView

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

นี่ควรเป็นคำตอบที่ยอมรับได้เนื่องจากวิธีการใช้ viewTreeObserver ทำให้เกิดการรั่วไหลของหน่วยความจำและต้องถูกลบออกด้วยตนเองมิฉะนั้นจะมีการเพิ่มผู้สังเกตการณ์แบบเลื่อนหลายคน
Ray Li

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

}

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

โปรดลองเพิ่มคำอธิบายเพื่อสนับสนุนโค้ดของคุณซึ่งจะทำให้ทุกคนเข้าใจแป้ง
Aniruddha Das

รหัสนี้คล้ายกับคำตอบอื่นมากใช่ไหม
Sergii
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.