我在安卓布局中有2个ScrollView,如何同步它们的滚动位置?
在ScrollView中有一个方法可以检查该视图是否已经滚动到底部,方法名为isAtBottom()
。该方法返回一个布尔值,表示当前内容是否滚动到了底部。
protected void onScrollChanged(int x, int y, int oldx, int oldy)
很不幸,谷歌从未想到我们需要访问它,这就是为什么他们将其保护起来并且没有添加 "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()方法已经为我们处理了任何循环条件,因此我们不需要担心。唯一需要注意的是,这种解决方案不能保证在将来的Android版本中有效,因为我们正在覆盖受保护的方法。
对Andy的解决方案进行改进: 在他的代码中,他使用了scrollTo方法,问题在于,如果您在一个方向上扔一个scrollview,然后在另一个方向上扔另一个scrollview,您会注意到第一个scrollview不会停止先前的扔动作。
这是因为scrollView使用computeScroll()执行它的flinging手势,并与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。(这有助于避免在滚动更改时出现无限循环)
我发现onOverScrolled是唯一可用于阻止scrollView抛掷的函数(但可能还有其他我错过的函数!)
为了访问此受保护的函数,您必须将此添加到ObservableScrollViewer中。
public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}
OnTouchListener
。然后重写 onTouch 方法,获取第一个 ScrollView 的滚动位置 ScrollViewOne.getScrollY()
并更新 ScrollViewTwo.scrollTo(0, ScrollViewOne.getScrollY());
。
protected
方法是用来重写的.. 否则就使用包私有或私有。 - dcow