Androidレイアウトに2つのScrollViewがあります。スクロール位置を同期するにはどうすればよいですか?
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のソリューションの改善:彼のコードでは、彼は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);
}
アクティビティにOnTouchListener
を単に実装しないのはなぜですか。次に、onTouchメソッドをオーバーライドし、最初のScrollViewOne.getScrollY()
のスクロール位置を取得し、ScrollViewTwo.scrollTo(0, ScrollViewOne.getScrollY());
を更新します
ちょうど別のアイデア... :)
Android support-v4パッケージでは、Android NestedScrollView
という名前の新しいクラスを提供します。
レイアウトXMLで<ScrollView>
ノードを<Android.support.v4.widget.NestedScrollView>
に置き換え、そのNestedScrollView.OnScrollChangeListener
をJavaで実装してスクロールを処理します。
それは物事を簡単にします。