同步ScrollView滚动位置 – android

我有我的android布局2 ScrollViews。 我怎样才能同步他们的滚动位置?

在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挂钩。

 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()代码负责处理任何循环条件,所以我们不需要担心。 唯一的警告是,这个解决scheme不能保证在未来的Android版本中工作,因为我们覆盖了一个受保护的方法。

安迪解决scheme的改进:在他的代码中,他使用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(但可能有其他人,我已经错过!)

为了访问这个function(这是保护),你必须添加到您的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支持NestedScrollView包中,Android提供了一个名为NestedScrollView的新类。

我们可以在layout xml中用<android.support.v4.widget.NestedScrollView>replace<ScrollView>节点,并在Java中实现它的NestedScrollView.OnScrollChangeListener来处理滚动。

这使事情变得简单。