同步ScrollView滚动位置 - android

Tim*_*Tim 94 android scroll

我的Android布局中有2个ScrollViews.如何同步他们的滚动位置?

小智 289

ScrollView中有一个方法...

protected void onScrollChanged(int x, int y, int oldx, int oldy)
Run Code Online (Sandbox Code Playgroud)

不幸的是,Google从未想过我们需要访问它,这就是为什么它们保护并且没有添加"setOnScrollChangedListener"钩子的原因.所以我们必须为自己做这件事.

首先我们需要一个接口.

package com.test;

public interface ScrollViewListener {

    void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy);

}
Run Code Online (Sandbox Code Playgroud)

然后我们需要覆盖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);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

我们应该在布局中指定这个新的ObservableScrollView类,而不是现有的ScrollView标记.

<com.test.ObservableScrollView
    android:id="@+id/scrollview1"
    ... >

    ...

</com.test.ObservableScrollView>
Run Code Online (Sandbox Code Playgroud)

最后,我们将它们放在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);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

scrollTo()代码为我们处理任何循环条件,因此我们不需要担心.唯一需要注意的是,此解决方案无法保证在未来的Android版本中有效,因为我们正在覆盖受保护的方法.


Tai*_*iko 11

安迪的解决方案的改进:在他的代码,他使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

with interceptScroll一个初始化为true的静态布尔值.(这有助于避免ScrollChanged上的无限循环)

onOverScrolled是我发现的唯一一个可以用来阻止scrollView抛出的函数(但可能还有其他我错过了!)

要访问此功能(受保护),您必须将其添加到ObservableScrollViewer

public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
    super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}
Run Code Online (Sandbox Code Playgroud)

  • 儿子真好! (2认同)

小智 5

为什么不在OnTouchListener您的活动中实施.然后覆盖onTouch方法,然后获取第一个的滚动位置 ScrollViewOne.getScrollY()并更新ScrollViewTwo.scrollTo(0, ScrollViewOne.getScrollY());

只是另一个想法...... :)

  • 这可以工作,但是当你触摸并放开时,滚动视图可以在你没有捕获之后再滚动一点. (6认同)