Я использую HorizontalScrollView
в макете, и мне нужно определить, что пользователь достиг начальной и конечной точки прокрутки.
Потому что ListView
я попробовал, onScrollListener
и можно найти начальную и конечную точки прокрутки.
Я пытался сделать то же самое в своем, Scrollview
но это не представляется возможным. Есть ли другие возможные способы достичь того, что мне нужно?
onStart
будет делать трюк:hsv.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {@Override public void onScrollChanged() {Log.i(TAG,"scroll:"+hsv.getScrollX());}});
в OnStart () , гдеhsv
являетсяHorizontalScrollView
работой.Ответы:
Каждый экземпляр View вызывает
getViewTreeObserver()
. Теперь, удерживая экземплярViewTreeObserver
, вы можете добавитьOnScrollChangedListener()
к нему с помощью методаaddOnScrollChangedListener()
.Вы можете увидеть больше информации об этом классе здесь .
Это позволяет вам быть в курсе каждого события прокрутки - но без координат. Однако вы можете получить их, используя
getScrollY()
илиgetScrollX()
изнутри слушателя.scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() { @Override public void onScrollChanged() { int scrollY = rootScrollView.getScrollY(); // For ScrollView int scrollX = rootScrollView.getScrollX(); // For HorizontalScrollView // DO SOMETHING WITH THE SCROLL COORDINATES } });
источник
hsv.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {@Override public void onScrollChanged() {Log.i(TAG,"scroll:"+hsv.getScrollX());}});
в OnStart () , гдеhsv
представляет собойHorizontalScrollView
произведение. Я подозреваю, что то же самое будет работать и для ScrollView.add
и нетset
, все слушатели будут сохраняться до тех пор, пока явно не будут удалены. Таким образом, анонимный класс, используемый в качестве реализации прослушивателя в примере, будет протекать (вместе со всем, на что он ссылается, то есть внешним классом).Это может быть очень полезно. Используйте
NestedScrollView
вместоScrollView
. Поддержка Библиотека 23,1 представилаOnScrollChangeListener
вNestedScrollView
. Итак, вы можете сделать что-то подобное.myScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() { @Override public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { Log.d("ScrollView","scrollX_"+scrollX+"_scrollY_"+scrollY+"_oldScrollX_"+oldScrollX+"_oldScrollY_"+oldScrollY); //Do something } });
источник
NestedScrollView
является частью библиотеки поддержки, егоsetOnScrollChangeListener
метод не требует минимальной версии.View
's, дляsetOnScrollChangeListener
которого требуется уровень API 23Вот производный HorizontalScrollView, который я написал для обработки уведомлений о прокрутке и окончании прокрутки. Он правильно обрабатывает, когда пользователь прекратил активную прокрутку и когда он полностью замедляется после того, как пользователь отпускает:
public class ObservableHorizontalScrollView extends HorizontalScrollView { public interface OnScrollListener { public void onScrollChanged(ObservableHorizontalScrollView scrollView, int x, int y, int oldX, int oldY); public void onEndScroll(ObservableHorizontalScrollView scrollView); } private boolean mIsScrolling; private boolean mIsTouching; private Runnable mScrollingRunnable; private OnScrollListener mOnScrollListener; public ObservableHorizontalScrollView(Context context) { this(context, null, 0); } public ObservableHorizontalScrollView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ObservableHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean onTouchEvent(MotionEvent ev) { int action = ev.getAction(); if (action == MotionEvent.ACTION_MOVE) { mIsTouching = true; mIsScrolling = true; } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { if (mIsTouching && !mIsScrolling) { if (mOnScrollListener != null) { mOnScrollListener.onEndScroll(this); } } mIsTouching = false; } return super.onTouchEvent(ev); } @Override protected void onScrollChanged(int x, int y, int oldX, int oldY) { super.onScrollChanged(x, y, oldX, oldY); if (Math.abs(oldX - x) > 0) { if (mScrollingRunnable != null) { removeCallbacks(mScrollingRunnable); } mScrollingRunnable = new Runnable() { public void run() { if (mIsScrolling && !mIsTouching) { if (mOnScrollListener != null) { mOnScrollListener.onEndScroll(ObservableHorizontalScrollView.this); } } mIsScrolling = false; mScrollingRunnable = null; } }; postDelayed(mScrollingRunnable, 200); } if (mOnScrollListener != null) { mOnScrollListener.onScrollChanged(this, x, y, oldX, oldY); } } public OnScrollListener getOnScrollListener() { return mOnScrollListener; } public void setOnScrollListener(OnScrollListener mOnEndScrollListener) { this.mOnScrollListener = mOnEndScrollListener; } }
источник
Вы можете использовать
NestedScrollView
вместоScrollView
. Однако при использовании Kotlin Lambda он не узнает, что вам нужен NestedScrollViewsetOnScrollChangeListener
вместо того, который находится в View (это уровень API 23). Вы можете исправить это, указав первый параметр как NestedScrollView.nestedScrollView.setOnScrollChangeListener { _: NestedScrollView, scrollX: Int, scrollY: Int, _: Int, _: Int -> Log.d("ScrollView", "Scrolled to $scrollX, $scrollY") }
источник
Если вы хотите узнать положение прокрутки представления, вы можете использовать следующую функцию расширения в классе View:
fun View?.onScroll(callback: (x: Int, y: Int) -> Unit) { var oldX = 0 var oldY = 0 this?.viewTreeObserver?.addOnScrollChangedListener { if (oldX != scrollX || oldY != scrollY) { callback(scrollX, scrollY) oldX = scrollX oldY = scrollY } } }
источник
вы можете определить собственный класс ScrollView и добавить интерфейс, который будет вызываться при прокрутке следующим образом:
public class ScrollChangeListenerScrollView extends HorizontalScrollView { private MyScrollListener mMyScrollListener; public ScrollChangeListenerScrollView(Context context) { super(context); } public ScrollChangeListenerScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public ScrollChangeListenerScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void setOnMyScrollListener(MyScrollListener myScrollListener){ this.mMyScrollListener = myScrollListener; } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if(mMyScrollListener!=null){ mMyScrollListener.onScrollChange(this,l,t,oldl,oldt); } } public interface MyScrollListener { void onScrollChange(View view,int scrollX,int scrollY,int oldScrollX, int oldScrollY); } }
источник
// --------Start Scroll Bar Slide-------- final HorizontalScrollView xHorizontalScrollViewHeader = (HorizontalScrollView) findViewById(R.id.HorizontalScrollViewHeader); final HorizontalScrollView xHorizontalScrollViewData = (HorizontalScrollView) findViewById(R.id.HorizontalScrollViewData); xHorizontalScrollViewData.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { int scrollX; int scrollY; scrollX=xHorizontalScrollViewData.getScrollX(); scrollY=xHorizontalScrollViewData.getScrollY(); xHorizontalScrollViewHeader.scrollTo(scrollX, scrollY); } }); // ---------End Scroll Bar Slide---------
источник
Помимо принятого ответа, вам нужно сохранить ссылку на слушателя и удалить, когда она вам не нужна. В противном случае вы получите исключение нулевого указателя для вашего ScrollView и утечки памяти ( упомянутого в комментариях к принятому ответу) .
Вы можете реализовать OnScrollChangedListener в своей активности / фрагменте.
MyFragment : ViewTreeObserver.OnScrollChangedListener
Добавьте его в scrollView, когда ваше представление будет готово.
scrollView.viewTreeObserver.addOnScrollChangedListener(this)
Удалите слушателя, когда он больше не нужен (например, onPause ())
scrollView.viewTreeObserver.removeOnScrollChangedListener(this)
источник