日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

Android獲取RecyclerView滑動(dòng)距離方法詳細(xì)講解_Android

作者:AllenC6 ? 更新時(shí)間: 2023-03-03 編程語(yǔ)言

先說(shuō)能用的究極解決方案,大家著急的直接復(fù)制走,以后想了解再過(guò)來(lái)看

沒(méi)有header,且所有Item的高度一致

    private fun getScrollYDistance(recyclerView: RecyclerView): Int? {
        kotlin.runCatching {
            val layoutManager = recyclerView.layoutManager as LinearLayoutManager
            val position = layoutManager.findFirstVisibleItemPosition()
            val firstVisibleChildView = layoutManager.findViewByPosition(position)
            val itemHeight = firstVisibleChildView!!.height
            return position * itemHeight - firstVisibleChildView.top
        }
        return null
    }

有一個(gè)header,其他所有Item高度一致

    var headerHeight = 0
    private fun getScrollYDistance(recyclerView: RecyclerView): Int? {
        kotlin.runCatching {
            val layoutManager = recyclerView.layoutManager as LinearLayoutManager
            val position = layoutManager.findFirstVisibleItemPosition()
            if (position == 0) {
                val headerView = layoutManager.findViewByPosition(0)
                headerHeight = headerView!!.height
            }
            val firstVisibleChildView = layoutManager.findViewByPosition(position)
            val itemHeight = firstVisibleChildView!!.height
            return if (position == 0) {
                position * itemHeight - firstVisibleChildView.top
            } else {
                (position - 1) * itemHeight - firstVisibleChildView.top + headerHeight
            }
        }
        return null
    }

有多個(gè)header,其他Item一致

   Integer[] headerHeightArray;
    private int getScollYDistance(){
        LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getRecyclerView().getLayoutManager();
        // 獲取第一個(gè)可見(jiàn)item的位置
        int position = layoutManager.findFirstVisibleItemPosition();
        // 獲取第一個(gè)可見(jiàn)item
        View firstVisiableChildView = layoutManager.findViewByPosition(position);
        // 必須考慮有沒(méi)有Header  預(yù)存下所有header的高度
        int headerCount = adapter.getHeaderCount();
        if (headerCount > 0) {
            if (headerHeightArray == null) {
                headerHeightArray = new Integer[headerCount];
            }
            if (position < headerCount) {
                View headerView_i = layoutManager.findViewByPosition(position);
                headerHeightArray[position] = headerView_i.getHeight();
            }
        }
        // 獲取第一個(gè)可見(jiàn)item的高度
        int itemHeight = firstVisiableChildView.getHeight();
        // 獲取第一個(gè)可見(jiàn)item的位置
        int distance = 0;
        if (position == 0) {
            distance = position * itemHeight - firstVisiableChildView.getTop();
        } else {
            int allHeaderHeight = 0;
            for (int i = 0; i < Math.min(position,headerCount); i++) {
                allHeaderHeight = allHeaderHeight + headerHeightArray[i];
            }
            distance = (position - Math.min(position,headerCount)) * itemHeight - firstVisiableChildView.getTop() + allHeaderHeight;
        }
        return distance;
    }

注意調(diào)用位置:

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    getScollYDistance();
                }
            });

試過(guò)的一些想法,都有一些問(wèn)題,有的可以彌補(bǔ),有的直接玩完

RecyclerView 雖然有g(shù)etScrollX() 和 getScrollY(), 但是測(cè)試發(fā)現(xiàn)這兩個(gè)函數(shù)總是返回0,太無(wú)語(yǔ)了。因此想到了下面幾種方法來(lái)實(shí)現(xiàn)獲取滑動(dòng)距離:

利用OnScrollListener

        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            private int totalDy = ;
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                totalDy -= dy;
            }
        });

如代碼所述,totalDy的確保存了 RecyclerView 的滑動(dòng)距離,但是當(dāng)我向下滑動(dòng) RecyclerView ,之后插入/刪除/移動(dòng) Item 的時(shí)候,totalDy 就變得不精確了;比如刪除或者插入新的Item,那么totalDy就不能再回歸到 0了。這個(gè)可以通過(guò)當(dāng)刪除或者插入時(shí)來(lái)對(duì)totalDy進(jìn)行加減相應(yīng)的高度。

totalDy = recyclerView.computeVerticalScrollOffset();

然而compute方法計(jì)算出的并不是滑動(dòng)的精確距離,stackOverflow上有答案解釋其為 item 的平均高度 * 可見(jiàn) item 數(shù)目,不是我們需要的精確距離。

totalDy = recyclerView.getChildAt().getTop();

依靠第一個(gè)item的滑動(dòng)距離來(lái)進(jìn)行動(dòng)畫(huà)的設(shè)置,但是根據(jù)該方法得出的 totalDy 在滑動(dòng)到一定程度后清零。

這是因?yàn)閞ecyclerViewl.getChildAt(0) 返回的永遠(yuǎn)是第一個(gè)可見(jiàn)的child,不是所有view list 的第一個(gè)child,因此這種用法是得不到滑動(dòng)距離的。

另外下面這三種用法都是等價(jià)的,都是獲取第一個(gè)可見(jiàn)的child:

       LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
       View firstVisiableChildView = this.getChildAt();
       View firstVisiableChildView = layoutManager.getChildAt()
       int position = layoutManager.findFirstVisibleItemPosition();
       View firstVisiableChildView = layoutManager.getChildAt(position)

但是下面這種就不是獲取第一個(gè)可見(jiàn)的child,而是獲得所有view list 的第一個(gè)child。但是滑動(dòng)一段距離后它總是返回null,即第一個(gè)child被recycle后,總是返回null。

//Don't use this function to get the first item, it will return null when the first item is recycled.
LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
View child2 = layoutManager.findViewByPosition();

原文鏈接:https://blog.csdn.net/m0_37707561/article/details/128641390

欄目分類
最近更新