ซิงโครไนซ์ตำแหน่งเลื่อน ScrollView - Android


96

ฉันมี 2 ScrollViews ในเลย์เอาต์ Android ของฉัน ฉันจะซิงโครไนซ์ตำแหน่งการเลื่อนได้อย่างไร?

คำตอบ:


290

มีวิธีการใน ScrollView ...

protected void onScrollChanged(int x, int y, int oldx, int oldy)

น่าเสียดายที่ Google ไม่เคยคิดว่าเราจะต้องเข้าถึงมันซึ่งเป็นสาเหตุที่ทำให้มันได้รับการปกป้องและไม่ได้เพิ่มตะขอ "setOnScrollChangedListener" ดังนั้นเราจะต้องทำเพื่อตัวเอง

อันดับแรกเราต้องมีอินเทอร์เฟซ

package com.test;

public interface ScrollViewListener {

    void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy);

}

จากนั้นเราต้องลบล้างคลาส ScrollView เพื่อให้ ScrollViewListener hook

package com.test;

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

public class ObservableScrollView extends ScrollView {

    private ScrollViewListener scrollViewListener = null;

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

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

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

    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldx, int oldy) {
        super.onScrollChanged(x, y, oldx, oldy);
        if(scrollViewListener != null) {
            scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
        }
    }

}

และเราควรระบุคลาส ObservableScrollView ใหม่นี้ในเลย์เอาต์แทนแท็ก ScrollView ที่มีอยู่

<com.test.ObservableScrollView
    android:id="@+id/scrollview1"
    ... >

    ...

</com.test.ObservableScrollView>

ในที่สุดเราก็รวบรวมมันทั้งหมดเข้าด้วยกันในคลาส Layout

package com.test;

import android.app.Activity;
import android.os.Bundle;

public class Q3948934 extends Activity implements ScrollViewListener {

    private ObservableScrollView scrollView1 = null;
    private ObservableScrollView scrollView2 = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.q3948934);

        scrollView1 = (ObservableScrollView) findViewById(R.id.scrollview1);
        scrollView1.setScrollViewListener(this);
        scrollView2 = (ObservableScrollView) findViewById(R.id.scrollview2);
        scrollView2.setScrollViewListener(this);
    }

    public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) {
        if(scrollView == scrollView1) {
            scrollView2.scrollTo(x, y);
        } else if(scrollView == scrollView2) {
            scrollView1.scrollTo(x, y);
        }
    }

}

รหัส scrollTo () ดูแลเงื่อนไขการวนซ้ำสำหรับเราดังนั้นเราจึงไม่จำเป็นต้องกังวลเกี่ยวกับเรื่องนี้ ข้อแม้เดียวคือโซลูชันนี้ไม่รับประกันว่าจะใช้งานได้กับ Android เวอร์ชันอนาคตเนื่องจากเรากำลังลบล้างวิธีการป้องกัน


สวัสดีแอนดี้ขอบคุณที่สละเวลาในการตอบคำถามนี้ - ทำให้ฉันก้าวไปข้างหน้า ขอบคุณอีกครั้ง. Tim
Tim

- และฉันก็ใช้รหัสนี้เหมือนกัน แต่มันกำลังทำให้ตัวชี้เป็นโมฆะคุณช่วยฉันได้ไหม
hemant

@hemant คุณช่วยชี้ให้เห็นได้ไหมว่า NullPointer ถูกโยนเข้ามาในบรรทัดใดและคุณกำลังใช้ Android เวอร์ชันใด
sulai

ฮีโร่ประจำวัน: ช่วยชีวิตฉัน! = D
Pedrão

สวัสดีแอนดี้ขอบคุณสำหรับรหัสมันใช้งานได้ดีฉันอยากรู้สิ่งหนึ่ง [ถ้าคุณหรือคนใดคนหนึ่งมี ans ถึงสิ่งนี้] - เมื่อฉันเลื่อน scrollView ของฉันเมธอด onscrollchanged จะไม่ลงทะเบียนพิกัด X และ Y ทั้งหมดในขณะที่ scrollview เคลื่อนที่ มันทำให้ฉันได้แค่ตำแหน่งเริ่มต้นและตำแหน่งสุดท้าย พูดสำหรับอดีต - ฉันเริ่มพุ่งจาก Y = 10 และปล่อยไว้ที่ Y = 30 จากนั้นความเร็วพุ่งไปที่ Y = 50 แล้วหยุด ดังนั้น onscroll จึงเปลี่ยนเฉพาะการลงทะเบียน - อาจเป็น 10, 11, 12..30 และ 49, 50 ฉันจะทำให้มันลงทะเบียนตำแหน่งกลางทั้งหมดได้อย่างไรและรับพิกัดทั้งหมดจาก 10 ถึง 50 ??
นักเล่นแร่แปรธาตุ

12

การปรับปรุงวิธีแก้ปัญหาของ Andy: ในโค้ดของเขาเขาใช้ scrollTo ปัญหาคือถ้าคุณเหวี่ยง scrollview หนึ่งไปในทิศทางเดียวแล้วเหวี่ยงอีกอันไปในทิศทางอื่นคุณจะสังเกตเห็นว่าอันแรกไม่ได้หยุดการพุ่งก่อนหน้าของเขา การเคลื่อนไหว.

นี่เป็นเพราะการที่ scrollView ใช้ computeScroll () ในการทำท่าทางเหวี่ยงและมันขัดแย้งกับ scrollTo

เพื่อป้องกันปัญหานี้เพียงตั้งโปรแกรม onScrollChanged ด้วยวิธีนี้:

    public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) {
    if(interceptScroll){
        interceptScroll=false;
        if(scrollView == scrollView1) {
            scrollView2.onOverScrolled(x,y,true,true);
        } else if(scrollView == scrollView2) {
            scrollView1.onOverScrolled(x,y,true,true);
        }
        interceptScroll=true;
    }
}

ด้วย interceptScroll บูลีนแบบคงที่เริ่มต้นเป็นจริง (สิ่งนี้ช่วยหลีกเลี่ยงการวนซ้ำที่ไม่มีที่สิ้นสุดบน ScrollChanged)

onOverScrolled เป็นฟังก์ชันเดียวที่ฉันพบซึ่งสามารถใช้เพื่อหยุด scrollView จากการเหวี่ยง (แต่อาจมีบางอย่างที่ฉันพลาดไป!)

ในการเข้าถึงฟังก์ชันนี้ (ซึ่งได้รับการป้องกัน) คุณต้องเพิ่มสิ่งนี้ใน ObservableScrollViewer ของคุณ

public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
    super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}

2
ช่างเป็นอะไรที่ดีมากลูกชาย!
FranciscoBouza

5

ทำไมไม่เพียงแค่นำไปใช้OnTouchListenerในกิจกรรมของคุณ จากนั้นแทนที่วิธีการ onTouch จากนั้นรับตำแหน่งเลื่อนของรายการแรก ScrollViewOne.getScrollY()และอัปเดตScrollViewTwo.scrollTo(0, ScrollViewOne.getScrollY());

แค่ความคิดอื่น ... :)


7
วิธีนี้สามารถใช้งานได้ แต่เมื่อคุณแตะและปล่อยมุมมองการเลื่อนสามารถเลื่อนได้อีกเล็กน้อยหลังจากที่คุณปล่อยซึ่งไม่ได้ถูกจับ
richy

ฉันจะอ้างอิง / รับการอ้างอิงของ scrollView ScrollViewOne ในกรณีนี้ใน java ได้อย่างไร
Bunny Rabbit

นอกจากนี้ยังมีวิธีอื่น ๆ ในการเลื่อน (เช่น onTrackballEvent ())
surfealokesea

เป็นความคิดที่ดีมาก แต่แทนที่จะรับและตั้งค่าตำแหน่งเลื่อน y มันง่ายกว่าเพียงแค่ส่งเหตุการณ์การสัมผัสไปที่มุมมองแบบเลื่อนที่สอง สิ่งนี้จะทำให้ "พุ่ง" ต่อไปในมุมมองแบบเลื่อนที่สอง MotionEvent newEvent = MotionEvent.obtain (เหตุการณ์); documentScrollView.dispatchTouchEvent (newEvent);
Eduard Mossinkoff

3

ในแพคเกจสนับสนุน Android-v4, Android NestedScrollViewให้ระดับใหม่ที่ชื่อว่า

เราสามารถแทนที่<ScrollView>โหนดด้วย<android.support.v4.widget.NestedScrollView>ในรูปแบบ xml และใช้งานNestedScrollView.OnScrollChangeListenerใน Java เพื่อจัดการกับการเลื่อน

นั่นทำให้สิ่งต่างๆง่ายขึ้น

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