Câu trả lời:
Có một phương pháp trong ScrollView ...
protected void onScrollChanged(int x, int y, int oldx, int oldy)
Thật không may, Google chưa bao giờ nghĩ rằng chúng tôi sẽ cần truy cập nó, đó là lý do tại sao họ bảo vệ nó và không thêm hook "setOnScrollChangedListener". Vì vậy, chúng tôi sẽ phải làm điều đó cho chính mình.
Đầu tiên chúng ta cần một giao diện.
package com.test;
public interface ScrollViewListener {
void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy);
}
Sau đó, chúng ta cần ghi đè lớp ScrollView, để cung cấp móc 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);
}
}
}
Và chúng ta nên chỉ định lớp ObservableScrollView mới này trong bố cục, thay vì các thẻ ScrollView hiện có.
<com.test.ObservableScrollView
android:id="@+id/scrollview1"
... >
...
</com.test.ObservableScrollView>
Cuối cùng, chúng ta tập hợp tất cả lại với nhau trong lớp 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);
}
}
}
Mã scrollTo () sẽ xử lý bất kỳ điều kiện vòng lặp nào cho chúng ta, vì vậy chúng ta không cần phải lo lắng về điều đó. Cảnh báo duy nhất là giải pháp này không được đảm bảo hoạt động trong các phiên bản Android trong tương lai, vì chúng tôi đang ghi đè một phương pháp được bảo vệ.
Một cải tiến đối với giải pháp của Andy: Trong mã của anh ấy, anh ấy sử dụng scrollTo, vấn đề là, nếu bạn lướt một lượt xem cuộn theo một hướng và sau đó lật một chế độ xem khác theo hướng khác, bạn sẽ nhận thấy rằng chế độ xem đầu tiên không dừng lần lướt trước đó của anh ta chuyển động.
Điều này là do thực tế là scrollView sử dụng computeScroll () để thực hiện các cử chỉ lướt và nó xung đột với scrollTo.
Để ngăn chặn điều này, chỉ cần lập trình onScrollChanged theo cách này:
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;
}
}
với intercept Cuộn một boolean tĩnh được khởi tạo thành true. (điều này giúp tránh các vòng lặp vô hạn trên ScrollChanged)
onOverScrolled là chức năng duy nhất tôi tìm thấy có thể được sử dụng để ngăn scrollView nhấp nháy (nhưng có thể có những chức năng khác mà tôi đã bỏ qua!)
Để truy cập chức năng này (được bảo vệ), bạn phải thêm chức năng này vào ObservableScrollViewer của bạn
public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}
Tại sao không chỉ thực hiện OnTouchListener
trong hoạt động của bạn. Sau đó ghi đè phương thức onTouch, rồi lấy vị trí cuộn của phương thức đầu tiên ScrollViewOne.getScrollY()
và cập nhậtScrollViewTwo.scrollTo(0, ScrollViewOne.getScrollY());
Chỉ là một ý tưởng khác ... :)
Trong gói Android support-v4, Android cung cấp một lớp mới có tên NestedScrollView
.
chúng ta có thể thay thế <ScrollView>
nút bằng <android.support.v4.widget.NestedScrollView>
xml bố cục và triển khai nó NestedScrollView.OnScrollChangeListener
trong Java để xử lý việc cuộn.
Điều đó làm cho mọi thứ dễ dàng hơn.