Android ListView 当前滚动位置 Y 像素

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12727594/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 11:35:26  来源:igfitidea点击:

Android ListView current scroll location Y pixels

androidlistviewscrollscroll-offset

提问by Juhani

I'm trying to detect when a list view is scrolled beyond certain fixed threshold in pixels (half way through the first item). Unfortunately listview's getScrollY() seems to always return 0 instad of the scroll position. Is there any way to get the actual scroll location by pixel?

我试图检测列表视图何时滚动超过以像素为单位的某个固定阈值(第一项的一半)。不幸的是,listview 的 getScrollY() 似乎总是返回滚动位置的 0 instad。有没有办法按像素获取实际滚动位置?

Here's the code I tried to use but as said it only returns 0.

这是我尝试使用的代码,但如上所述它只返回 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");
    }
});

回答by Cyril Mottier

There is no notion of Y scroll for a ListView in Android simply because the total height of the content is unknown. Only the height of the displayed content is known.

Android 中的 ListView 没有 Y 滚动的概念,因为内容的总高度是未知的。只有显示内容的高度是已知的。

However it is possible to get the current position/Y scroll of a visible item using the following hack:

但是,可以使用以下 hack 获取可见项目的当前位置/Y 滚动:

getListView().getChildAt(0).getTop();

回答by Tai Le Anh

A refactor code of Malachiasz's answer. This function is used for dynamic row's height.

Malachiasz 答案的重构代码。该函数用于动态行高。

Call onScroll listener

调用 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 function

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

回答by Andrey Tuzov

Maybe it will be useful for someone. Code of previous answer's will not work when the list is scrolled fast. Because in this case firstVisiblePosition may be change irregular. In my code I do not use an array to store positions

也许它对某人有用。当列表快速滚动时,先前答案的代码将不起作用。因为在这种情况下 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
            }
        }
    })
}

Then we can use when a listview is scrolled beyond threshold

然后我们可以在列表视图滚动超过阈值时使用

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 - can be used for animation

isScrollWorking - 可用于动画

回答by Rahul Ogale

You need two things to precisely define the scroll position of a listView:

您需要做两件事来精确定义 listView 的滚动位置:

To get current position:

获取当前位置:

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

To set the position:

要设置位置:

listView.setSelectionFromTop(firstVisiblePosition,0);
// Note the '-' sign...  
listView.scrollTo(0,-topEdge);

回答by Lalit Poptani

You can try implementing OnTouchListenerand override its onTouch(View v, MotionEvent event)and get the x and y using event.getX()and event.getY(). I had just created a demo for swipe on ListView row that will enable a delete button for deleting a particular item from the ListView. You can check the source code from my github as ListItemSwipe.

您可以尝试实现OnTouchListener并覆盖它onTouch(View v, MotionEvent event)并使用event.getX()and获取 x 和 y event.getY()。我刚刚创建了一个用于在 ListView 行上滑动的演示,它将启用用于从 ListView 中删除特定项目的删除按钮。你可以从我的 github 中查看源代码作为ListItemSwipe.