ScrollView 스크롤 위치 동기화-Android


95

내 안드로이드 레이아웃에 2 개의 ScrollView가 있습니다. 스크롤 위치를 어떻게 동기화 할 수 있습니까?

답변:


289

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

}

그런 다음 ScrollViewListener 후크를 제공하기 위해 ScrollView 클래스를 재정의해야합니다.

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

}

그리고 레이아웃에 기존 ScrollView 태그 대신이 새로운 ObservableScrollView 클래스를 지정해야합니다.

<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 버전에서 작동하지 않을 수 있다는 것입니다.


안녕하세요 Andy 시간을내어이 답변을 올려 주셔서 감사합니다. 다시 한 번 감사드립니다. Tim
Tim

-Andy 나는 또한 코드를 사용하고 있지만 그것은 나에게 널 포인터 기대를 던지고 있습니다 당신이 나를 도울 수 있습니까
hemant

@hemant NullPointer가 어느 줄에 표시되고 어떤 Android 버전을 사용하고 있는지 지적 해 주시겠습니까?
sulai

오늘의 영웅 : 내 생명을 구했습니다! = D
Pedrão 2013-08-14

안녕 Andy, 코드 주셔서 감사합니다. 잘 작동합니다. 한 가지를 알고 싶습니다. [당신이나 누군가가 ans를 가지고 있다면. to this]-scrollView를 튕길 때 onscrollchanged 메서드는 scrollview가 이동하는 동안 모든 X 및 Y 좌표를 등록하지 않습니다. 시작 위치와 마지막 위치 만 알려줍니다. 예를 들어, 나는 Y = 10에서 플링을 시작하고 Y = 30으로 떠난 다음 플링 속도를 Y = 50으로 가져간 다음 중지합니다. 그래서 onscrollchanged 단지 레지스터-아마도 10, 11, 12..30 그리고 49, 50. 모든 중간 위치도 등록하고 10에서 50까지의 모든 좌표를 얻으려면 어떻게해야합니까 ??
연금술사

11

Andy의 솔루션 개선 : 그의 코드에서 그는 scrollTo를 사용합니다. 문제는 한 방향으로 스크롤 뷰를 던진 다음 다른 방향으로 다른 방향으로 던지면 첫 번째가 이전 플링을 중지하지 않는다는 것입니다. 운동.

이는 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을 사용하면 정적 부울이 true로 초기화됩니다. (이것은 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

이 경우 Java에서 scrollView ScrollViewOne의 참조 / 굴절을 어떻게 얻을 수 있습니까?
Bunny Rabbit

스크롤하는 다른 방법도 있습니다 (예 : onTrackballEvent ())
surfealokesea 2013

매우 좋은 생각이지만 스크롤 y 위치를 가져 와서 설정하는 대신 터치 이벤트를 두 번째 스크롤 뷰로 전달하는 것이 더 쉽습니다. 이것은 또한 두 번째 스크롤 뷰에서 "플링"을 계속 유지합니다. MotionEvent newEvent = MotionEvent.obtain (event); documentsScrollView.dispatchTouchEvent (newEvent);
Eduard Mossinkoff

3

Android support-v4 패키지에서 Android는 NestedScrollView.

레이아웃 xml에서 <ScrollView>노드를 교체 하고 스크롤을 처리하기 위해 Java로 <android.support.v4.widget.NestedScrollView>구현할 NestedScrollView.OnScrollChangeListener수 있습니다.

그것은 일을 더 쉽게 만듭니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.