31

リストビューがピクセル単位の特定の固定しきい値を超えてスクロールされたとき(最初のアイテムの途中)を検出しようとしています。残念ながら、listviewのgetScrollY()は、常にスクロール位置の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");
    }
});
4

5 に答える 5

53

コンテンツの全体の高さが不明であるという理由だけで、AndroidのListViewにYスクロールの概念はありません。表示されたコンテンツの高さのみがわかります。

ただし、次のハックを使用して、表示されているアイテムの現在の位置/Yスクロールを取得することは可能です。

getListView().getChildAt(0).getTop();
于 2012-10-04T13:15:23.503 に答える
2

マラキアシュの答えのリファクタリングコード。この関数は、動的な行の高さに使用されます。

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;
    }
于 2017-09-20T08:21:41.013 に答える
1

listViewのスクロール位置を正確に定義するには、次の2つが必要です。

現在の位置を取得するには:

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);
于 2020-03-13T13:26:52.253 に答える
0

実装OnTouchListenerしてオーバーライドし、とを使用しonTouch(View v, MotionEvent event)てxとyを取得してみてください。ListViewの行をスワイプして、ListViewから特定のアイテムを削除するための削除ボタンを有効にするデモを作成しました。あなたは私のgithubからのソースコードをとしてチェックすることができます。event.getX()event.getY()ListItemSwipe

于 2012-10-04T13:04:18.723 に答える
0

多分それは誰かのために役立つでしょう。リストを高速でスクロールすると、前の回答のコードは機能しません。この場合、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-アニメーションに使用できます

于 2018-12-06T10:37:01.130 に答える