Android ListView текущее положение прокрутки Y пикселей

Я пытаюсь определить, когда представление списка прокручивается за пределы определенного фиксированного порога в пикселях (на полпути через первый элемент). К сожалению, getScrollY () listview, кажется, всегда возвращает 0 instad позиции прокрутки. Есть ли способ получить фактическое местоположение прокрутки по пикселям?

Вот код, который я пытался использовать, но, как я уже сказал, возвращает только 0.

getListView().setOnScrollListener(new AbsListView.OnScrollListener() {
    public void onScroll(AbsListView view, int firstVisibleItem,
                         int visibleItemCount, int totalItemCount) {
        Log.d("scroll", "scroll: " + getListView().getScrollY());
    }

    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState == 0)
        Log.d("scroll", "scrolling stopped");
    }
});

person Juhani    schedule 04.10.2012    source источник
comment
Правильное решение   -  person Sarasranglt    schedule 24.02.2016


Ответы (5)


Нет понятия прокрутки Y для ListView в Android просто потому, что общая высота содержимого неизвестна. Известна только высота отображаемого содержимого.

Однако можно получить текущую позицию / прокрутку Y видимого элемента, используя следующий прием:

getListView().getChildAt(0).getTop();
person Cyril Mottier    schedule 04.10.2012
comment
это больше не работает. вам нужно добавить высоту всех предыдущих элементов первого видимого представления к этому фрагменту кода. Некоторые внутренние API недавно изменились. Я надеюсь, что api будет включать в себя простую функцию для получения этого значения в какой-то момент. Все существующие решения являются хакерскими и неизбежно выйдут из строя с будущими версиями API. Никогда не следует связываться с дочерними представлениями списка - person Radu Simionescu; 10.10.2014

Код рефакторинга ответа Малахиаса. Эта функция используется для динамической высоты строки.

Вызов слушателя onScroll

mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (mCardsListView.getChildCount() > 0) {
                    int scrollY = getScrollY();
                }
            }
        });

функция getScrollY

private Dictionary<Integer, Integer> mListViewItemHeights = new Hashtable<Integer, Integer>(); 
private int getScrollY() {
        View child = mCardsListView.getChildAt(0); //this is the first visible row
        if (child == null) return 0;

        int scrollY = -child.getTop();

        mListViewItemHeights.put(mCardsListView.getFirstVisiblePosition(), child.getHeight());

        for (int i = 0; i < mCardsListView.getFirstVisiblePosition(); ++i) {
            Integer hei = mListViewItemHeights.get(i);

            //Manual add hei each row into scrollY
            if (hei != null)
                scrollY += hei;
        }

        return scrollY;
    }
person Tai Le Anh    schedule 20.09.2017

Для точного определения позиции прокрутки listView вам нужны две вещи:

Чтобы узнать текущую позицию:

int firstVisiblePosition = listView.getFirstVisiblePosition(); 
int topEdge=listView.getChildAt(0).getTop(); //This gives how much the top view has been scrolled.

Чтобы установить позицию:

listView.setSelectionFromTop(firstVisiblePosition,0);
// Note the '-' sign...  
listView.scrollTo(0,-topEdge);
person Rahul Ogale    schedule 13.03.2020

Вы можете попробовать реализовать OnTouchListener и переопределить его onTouch(View v, MotionEvent event) и получить x и y с помощью event.getX() и event.getY(). Я только что создал демонстрацию для прокрутки строки ListView, которая активирует кнопку удаления для удаления определенного элемента из ListView. Вы можете проверить исходный код на моем github как ListItemSwipe.

person Lalit Poptani    schedule 04.10.2012
comment
Это не вариант для оси Y, поскольку ListView прокручивается в зависимости от скорости MotionEvent. - person Dmitry Zaytsev; 24.06.2013

Может кому будет полезно. Код предыдущего ответа не будет работать при быстрой прокрутке списка. Потому что в этом случае firstVisiblePosition может изменяться нерегулярно. В моем коде я не использую массив для хранения позиций

fun setOnTouchScrollListener(lv: AbsListView, onTouchScrollListener: (isDown: Boolean, offset: Int?, isScrollWorking: Boolean) -> Unit) {

    var lastItemPosition: Int = -1
    var lastItemTop: Int? = null
    var lastItemHeight: Int? = null
    var lastScrollState: Int? = AbsListView.OnScrollListener.SCROLL_STATE_IDLE

    lv.setOnScrollListener(object : AbsListView.OnScrollListener {

        override fun onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) {
            val child = lv.getChildAt(0)
            var offset: Int? = null
            var isDown: Boolean? = if (firstVisibleItem == lastItemPosition || lastItemPosition == -1) null else firstVisibleItem > lastItemPosition
            val dividerHeight = if (lv is ListView) lv.dividerHeight else 0
            val columnCount = if (lv is GridView) lv.numColumns else 1

            if (child != null) {
                if (lastItemPosition != -1) {
                    when (firstVisibleItem - lastItemPosition) {
                        0 -> {
                            isDown = if (lastItemTop == child.top) null else lastItemTop!! > child.top
                            offset = Math.abs(lastItemTop!! - child.top)
                        }
                        columnCount -> offset = lastItemHeight!! + lastItemTop!! - child.top + dividerHeight
                        -columnCount -> offset = child.height + child.top - lastItemTop!! + dividerHeight
                    }
                }

                lastItemPosition = firstVisibleItem
                lastItemHeight = child.height
                lastItemTop = child.top

                if (isDown != null && (offset == null || offset != 0)
                        && lastScrollState != AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
                    onTouchScrollListener(isDown, offset, true)
                }
            }
        }

        override fun onScrollStateChanged(view: AbsListView, scrollState: Int) {
            lastScrollState = scrollState
            if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
                onTouchScrollListener(true, 0, false)
                lastItemPosition = -1
                lastItemHeight = null
                lastItemTop = null
            }
        }
    })
}

Затем мы можем использовать, когда список прокручивается за пределы порога

private var lastThresholdOffset = 0
private var thresholdHeight = some value

setOnTouchScrollListener(listView) { isDown: Boolean, offset: Int?, isScrollWorking: Boolean ->
    val offset = offset ?: if (isDown) 0 else thresholdHeight
    lastThresholdOffset = if (isDown) Math.min(thresholdHeight, lastThresholdOffset + offset)
    else Math.max(0, lastThresholdOffset - offset)

    val result = lastThresholdOffset > thresholdHeight
}

isScrollWorking - может использоваться для анимации

person Andrey Tuzov    schedule 06.12.2018