web-dev-qa-db-ja.com

ScrollViewスクロール位置の同期-android

Androidレイアウトに2つのScrollViewがあります。スクロール位置を同期するにはどうすればよいですか?

94
Tim

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の将来のバージョンで動作することが保証されていないことです。

289
Andy

Andyのソリューションの改善:彼のコードでは、彼はscrollToを使用しています。問題は、1つのスクロールビューを一方向に投げてから別のスクロールビューを別の方向に投げると、最初のスクロールビューが彼の前の投げを停止しないことに気づくでしょう移動。

これは、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);
}
11
Taiko

アクティビティにOnTouchListenerを単に実装しないのはなぜですか。次に、onTouchメソッドをオーバーライドし、最初のScrollViewOne.getScrollY()のスクロール位置を取得し、ScrollViewTwo.scrollTo(0, ScrollViewOne.getScrollY());を更新します

ちょうど別のアイデア... :)

5
Aaron Newton

Android support-v4パッケージでは、Android NestedScrollViewという名前の新しいクラスを提供します。

レイアウトXMLで<ScrollView>ノードを<Android.support.v4.widget.NestedScrollView>に置き換え、そのNestedScrollView.OnScrollChangeListenerをJavaで実装してスクロールを処理します。

それは物事を簡単にします。

3
wangzhangjian