Синхронизировать позиции прокрутки ScrollView - Android
У меня есть 2 ScrollViews в моем макете Android. Как я могу синхронизировать их позиции прокрутки?
4 ответа
В 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() заботится о любых условиях цикла для нас, поэтому нам не нужно беспокоиться об этом. Единственное предостережение в том, что это решение не гарантированно будет работать в будущих версиях Android, потому что мы переопределяем защищенный метод.
Усовершенствование решения Энди: в его коде он использует 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 (но могут быть и другие, которые я пропустил!)
Чтобы получить доступ к этой функции (которая защищена), вы должны добавить ее в свой 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
,
мы можем заменить <ScrollView>
узел с <android.support.v4.widget.NestedScrollView>
в макете XML, и реализует его NestedScrollView.OnScrollChangeListener
в Java для обработки прокрутки.
Это делает вещи проще.