Вопрос по android – Могу ли я иметь OnScrollListener для ScrollView?

126

Я используюHorizontalScrollView в макете, и мне нужно определить, пользователь достиг начальной и конечной точки прокрутки.

ЗаListView Я попробовалonScrollListener и можно найти начальную и конечную точку прокрутки.

Я пытался сделать то же самое в моемScrollview но это кажется невозможным. Есть ли другие возможные способы добиться того, что мне нужно.

Заранее спасибо.

Это возможно. См. Ответ пользователя 2695685. Короче следующее вonStart сделает свое дело:hsv.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {@Override public void onScrollChanged() {Log.i(TAG,"scroll:"+hsv.getScrollX());}}); в onStart () гдеhsv этоHorizontalScrollView работает. JohnnyLambada
Почему в Android так сложно обнаружить событие прокрутки с помощью ScrollView? Это чокнутый имо. worked
примите любой полезный ответ .. если еще выложите свой собственный ответ .. Ranjith Kumar

Ваш Ответ

7   ответов
356

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все слушатели будут сохраняться до тех пор, пока они не будут удалены явно. Таким образом, утечет анонимный класс, используемый в качестве реализации слушателя в образце (наряду со всем, на что он ссылается, т.е. внешним классом).
это должно быть помечено как правильный ответ.
Вы должны сначала проверитьViewTreeObserver.isAlive()
Вероятно, глупый вопрос, но что такое rootScrollView?
1

который будет вызываться при scolling. вот так:

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);
}

}

3

вы можете использовать следующую функцию расширения в классе 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
        }
    }
}
17

которое я написал для обработки уведомлений о прокрутке и окончании прокрутки. Он правильно обрабатывает, когда пользователь прекратил активную прокруткуand когда он полностью замедляется после того, как пользователь отпускает:

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) {
            if (mIsTouching && !mIsScrolling) {
                if (mOnScrollListener != null) {
                    mOnScrollListe,ner.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;
    }

}
Это на самом деле работает! и нет необходимости в SDK & gt; 23 за это :)
Кажется, что это лучше, чем использование метода ViewTreeObserver. Просто потому, что когда у вас есть действие, когда у вас загружено несколько фрагментов (например, 3 фрагмента со скользящими вкладками) с ListViews и ScrollViews, и вам нужно зарегистрировать события для конкретного представления. Принимая во внимание, что если ViewTreeObserver зарегистрирован, он будет запускать события, даже если он не является активным представлением.
@ZaBlanc - Не могли бы вы рассказать мне, как инициализировать этот класс и слушателей из моего Activity, который содержит ScrollView? Я реализовал это очень хорошо, но слушатели пока не возвращают никаких значений.
2

NestedScrollView вместоScrollView, Однако при использовании Kotlin Lambda он не будет знать, что вам нужен NestedScrollView.setOnScrollChangeListener вместо того, что на View (который является уровнем API 23). Это можно исправить, указав первый параметр как NestedScrollView.

nestedScrollView.setOnScrollChangeListener { _: NestedScrollView, scrollX: Int, scrollY: Int, _: Int, _: Int ->
    Log.d("ScrollView", "Scrolled to $scrollX, $scrollY")
}
Это должен быть принятый ответ, потому что метод, использующий viewTreeObserver, вызывает утечки памяти и должен быть удален вручную, иначе будет добавлено несколько наблюдателей прокрутки.
38

использованиеNestedScrollView вместоScrollView, Библиотека поддержки 23.1 представилаOnScrollChangeListener вNestedScrollView. So you can do something like this.

 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 в качестве горизонтальной прокрутки? Не могу найти ни одного ресурса
Требуется уровень API 23, т.е. Android M.
@ Ошеломлен & APOS; п & APOS; запутатьсяNestedScrollView является частью библиотеки поддержки, егоsetOnScrollChangeListener Метод не имеет минимального требования к версии.
Определенно проще, чем отслеживать, добавили ли вы прослушиватель ранее с помощью getViewTreeObserver (). Спасибо!
Что если я хочу использовать горизонтальную прокрутку?
1
    // --------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---------
Этот код очень похож на другойanswerне так ли?
Этот код можно использовать ниже API17.
пожалуйста, попробуйте добавить описание, чтобы поддержать ваш код, который позволит всем понять тест

Похожие вопросы