1. 程式人生 > >RecyclerView Item 的懸浮效果(吸附效果)的實現

RecyclerView Item 的懸浮效果(吸附效果)的實現

在參考文章中,實現的是如下效果:
這裡寫圖片描述

實現的基本原理就是在一個 FrameLayout 中,設定一個 RV,然後在設定一個和 ItemView 一樣佈局結構以及樣式的懸浮條,然後懸浮條根據條件動態設定位置。

而該文章中博主也說明了這種效果的實現方案,但那是在 RV 的 Item 只有一個層級的情況下,即所有的 ItemView 都是同一型別的,而我是在使用了 drakeet 大佬的 MultiType,實現了 資料扁平化處理
這裡寫圖片描述

我需要讓下圖的 RV 也實現那種效果:
這裡寫圖片描述
雖然存在 Post 和 Comment 兩種型別的 ItemView,但是由於扁平化的處理,兩種 ItemView 都處於同一層次結構,而不是巢狀的關係。即兩種 ItemView 都 RV 的直接 ItemView,並且其中某些 Post 型別的 ItemView 可能會不存在附屬的 Comment ItemView。這種情況下,如果完全按照參考文章的那種實現方法的話,則會得不到預期的效果,下圖為預期效果圖:
這裡寫圖片描述

當然,主要的思想根據原參考文章的類似,但是在一些細節方面就需要做一下修改,這本例的實現中,RV 的兩種 ItemView 都是一個簡答的 TextView,只不過是在 Adapter 中動態設定樣式而已,因此懸浮條也是一個簡單的 TextView,且高度、樣式都要與 Post ItemView 的樣式一樣。

然後下面是核心程式碼,說明也依附在程式碼註釋上了,其中 mCurrentPosition 初始值為 0,因為在本次演示中不存在 HraderView,如果存在的話,則 mCurrentPosition 初始值應為第一個 Post ItemView 的 position

rv.addOnScrollListener(new
RecyclerView.OnScrollListener() { LinearLayoutManager linearLayoutManager = (LinearLayoutManager) rv.getLayoutManager(); int mSuspensionHeight; @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // mSuspensionBar.getHeight()的高度的獲取如果是在 onCreate() 或者是
// 在 RecyclerView.OnScrollListener 被初始化的時候去獲取,獲得的結果 // 會為 0,因此此時 mSuspensionBar 還沒有初始化完成 mSuspensionHeight = mSuspensionBar.getHeight(); int firstVisPos = linearLayoutManager.findFirstVisibleItemPosition(); Object firstVisibleItem = items.get(firstVisPos); Object nextItem = items.get(firstVisPos + 1); View nextView = linearLayoutManager.findViewByPosition(firstVisPos + 1); //下滑情況下 if (dy > 0) { //只有第一個可見的 Item 的下一個 Item 的型別 //為 Post型別時才需要動態設定效果 if (nextItem instanceof Post) { if (nextView.getTop() <= mSuspensionHeight) { //被頂掉的效果 mSuspensionBar.setY(-(mSuspensionHeight - nextView.getTop())); } else { //否則就直接回到 Y = 0 的位置 mSuspensionBar.setY(0); } } //判斷是否需要更新懸浮條 if (mCurrentPosition != firstVisPos && firstVisibleItem instanceof Post) { mCurrentPosition = firstVisPos; //根據 mCurrentPosition 的值,更新 mSuspensionBar updateSuspensionBar(); mSuspensionBar.setY(0); } } else {//上滑情況 // 1、nextItem -> Post and firstVisibleItem -> Comment mCurrentPosition = ((Comment) firstVisibleItem).getParentPostPosition() // 2、nextItem -> Post and firstVisibleItem -> Post mCurrentPosition = firstVisPos // 3、nextItem -> Comment and firstVisibleItem -> Comment mSuspensionBar 不動 // 4、nextItem -> Comment and firstVisibleItem -> Post mSuspensionBar 不動 if (nextItem instanceof Post) { mCurrentPosition = firstVisibleItem instanceof Post ? firstVisPos : ((Comment) firstVisibleItem).getParentPostPosition(); updateSuspensionBar(); if (nextView.getTop() <= mSuspensionHeight) { //被頂掉的效果 mSuspensionBar.setY(-(mSuspensionHeight - nextView.getTop())); } else { mSuspensionBar.setY(0); } } } } });

如果對於上面的程式碼有所疑惑,其實可以將 mSuspensionBar 的背景設定為不同的顏色,同時設定一下透明度,就可以看到其原本的運作狀態了,如下圖,其中 mSuspensionBar.setY(0) 時當效果尤為明顯:
這裡寫圖片描述

其中,較為特殊的就是上滑的情況了,在上面的程式碼註釋中也有說明,上滑時總共有四種情況:

1、nextItem -> Post and firstVisibleItem -> Comment       mCurrentPosition = ((Comment) firstVisibleItem).getParentPostPosition()
2、nextItem -> Post and firstVisibleItem -> Post          mCurrentPosition = firstVisPos
3、nextItem -> Comment and firstVisibleItem -> Comment    mSuspensionBar 不動
4、nextItem -> Comment and firstVisibleItem -> Post       mSuspensionBar 不動

其中 -> 符號表示該 Item 對應的具體型別,只有頭兩種情況下,mSuspensionBar 才需要根據具體的情況設定動態效果,剩下的兩種情況下只要固定不動就可以了。

還需要說明的是,當 nextItem -> Post and firstVisibleItem -> Comment 時,正常情況是無法知道第一個可見 Item (即 firstVisibleItem )所附屬於的 Post 的 position,因此需要在初始化這些 Comment Item 的時候就設定好其附屬於的 Post 的 position,然後動態獲取。

就像下面的程式碼,會在初始化 Comment 元素時為其設定所附屬的 Post 的 position

//模擬資料
List<Post> list = new ArrayList<>();
int index = 0;
int parentPostPos;
Random random = new Random();
for (int i = 0; i < 10; i++) {
    Post post = new Post("pos = " + index);
    parentPostPos = index;
    list.add(post);
    index++;
    int k = random.nextInt(5);
    post.comments = new ArrayList<>();
    for (int j = 0; j < k; j++) {
        Comment comment = new Comment("pos = " + index, parentPostPos);
        post.comments.add(comment);
        index++;
    }
}

最後,再推薦一篇實現本文效果的文章:

在該篇文章中的實現,是利用了 recyclerView.addItemDecoration() 來自定義 ItemDecoration 實現的效果,這種方式實現了與業務的解耦,但在具體實現上相比上面的實現更加複雜一點,而且在遇到第三方的涉及 RV 的框架時,就可能需要根據具體的框架去進行相應的修改了,如在使用 MultiType 時,就不是那麼好契合了。

相關推薦

RecyclerView Item懸浮效果吸附效果實現

在參考文章中,實現的是如下效果: 實現的基本原理就是在一個 FrameLayout 中,設定一個 RV,然後在設定一個和 ItemView 一樣佈局結構以及樣式的懸浮條,然後懸浮條根據條件動態設定位置。 而該文章中博主也說明了這種效果的實現方

recyclerviewitem新增選中效果多選

大體實現思路: 使用相對佈局,在recyclerview的item整體佈局底層新增一個CheckBox,在adapter中引用一個Map標記選中CheckBox,然後在bandview中給CheckBox setOnCheckedChangeListener改變CheckB

微信小程式tab導航+滾動頂部吸附效果開發例項

<!-- scroll導航欄 --> <view class='scrollBox2 fix-news' wx:if="{{fixTop<scrollTop}}"&g

原生js三種選項卡效果輪播

col val 還在 log pla absolut 自動播放 div pac 第三種:定時輪播切換(我這邊定時是2s) <!DOCTYPE html> <html> <head> <meta charset="utf-8"

原生js三種選項卡效果點擊

eight void log utf 觸發 nts lin type position 第一種:選項卡單擊點擊切換 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /&g

微信小程序左右滑動切換圖片酷炫效果效果

bin select ans for image pac psi border als   開門見山,先上效果吧!感覺可以的用的上的再往下看。   心動嗎?那就繼續往下看!   先上頁面結構吧,也就是wxml文件,其實可以理解成微信自己封裝過的html,這個不多說了,不懂

Unity實現震屏效果螢幕抖動

     通過設定相機的Viewport Rect 來實現,將下面的指令碼掛在相機上,設定enabled=true就可實現螢幕震動效果。 using System.Collections; using System.Collections.Generic; usin

npm run build 打包後,如何執行在本地檢視效果Nginx服務

        這段時間,有點時間,研究了一下vue 打包的很慢的問題。但是當我 npm run build 打包後,在本地檢視效果的時候,活生生被我老大鄙視了,因為我打開了XAMPP。他說:你怎麼不用Nginx啊?用這個一堆的路徑問題!!!!!! 然後我就去研究了N

npm run build 打包後,如何運行在本地查看效果Nginx服務

get 工具 下載 inf 使用 執行 是我 map lan 這段時間,有點時間,研究了一下vue 打包的很慢的問題。但是當我 npm run build 打包後,在本地查看效果的時候,活生生被我老大鄙視了,因為我打開了XAMPP。他說:你怎麽不用Nginx

jquery 實現動畫效果各種方法

asc func 綜合 oat 代碼 jquer 一秒 遞歸 pan 1.show()和hide()和toggle()(這是show和hide的一個綜合,一個按鈕就實現顯示和隱藏) 效果: 代碼: <button type="button" class="show"

微信小程式實現跑馬燈效果完整程式碼

在微信小程式 裡實現跑馬燈效果,類似滾動字幕或者滾動廣告之類的,使用簡單的CSS樣式控制,沒用到JS,效果如下圖: Wxml程式碼: <!--跑馬燈 Linyufan.com--> <view class="marquee_container" st

svg 環形進度條加讀取進度效果讀數效果-- 移動端 rem 適配

專案需求做一個環形進度條的效果需要有一個讀數的效果,在網上查閱相關資料後整理了下 gif 效果如下,錄製的不是很流暢多停留下時間看下 都是動態的效果 程式碼如下 <!DOCTYPE html> <html lang="en">

移動端阻止瀏覽器中預設元素滑動回彈效果橡皮筋效果

在js檔案中加如下程式碼: document.addEventListener('touchstart',function(e){ e.preventDefault(); //

jquery-fly實現新增購物車拋物線效果angular版

<!DOCTYPE html> <html ng-app="myApp"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"

實現一個垂直跑馬燈的效果垂直公告

實現一個簡單的跑馬燈的效果,類似於App裡面的通知:恭喜XXX獲得了什麼什麼的效果。 首先先匯入兩個工具類 import android.app.Activity; import android.content.Context; import and

詳解vue2.0 使用動態元件實現 Tab 標籤頁切換效果vue-cli

在 vue 中,實現 Tab 切換主要有三種方式:使用動態元件,使用 vue-router 路由,使用第三方外掛。因為這次完成的功能只是簡單切換元件,再則覺得使用路由切換需要改變地址略微麻煩,所以使用的是動態元件實現,如果是在大型應用上,可能使用 vue-router 會方便

用input輸入框實現好看的複選框效果css+jq

做畢設果然是道阻且長QAQ,在用到一個複選框的時候由於嫌棄複選框實在太醜了,就自己做了一個。其中沒有用到任何圖片,用css和jQuery實現。 廢話不多說直接看最後效果: html元素的設計如下

MIUI 拖動視差效果阻尼效果/橡皮筋效果

Parallax 專案地址:xiaoyanger0825/Parallax  簡介:MIUI 拖動視差效果(阻尼效果/橡皮筋效果) 更多:作者   提 Bug   官網    標籤:

res-----不同圖片實現動畫效果幀動畫

1、準備幾張圖片(可命名為a1-a6) 2、在drawable資料夾下新建xml,內容如下 <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.androi

沉浸式的簡單實現效果很簡單

在Activity中實現這個方法,就可以實現沉浸式,但是必須在5.0以上的系統中實現 public void onWindowFocusChanged(boolean hasFocus) {//沉浸式 super.onWindowFocusChanged(hasFocus