每個元素知道自己的序号,可以根據需要修改自己的内容、大小等資訊。
此外支援了ScrollBar,支援橫向、縱向及正反向。

在關閉Mask後可以看到,隻有當需要的時候才動态執行個體化元素,使用完後回收。
最原始版本的代碼是@ivomarel的InfinityScroll。我改到後來,基本和原始版沒啥相同的了。
原代碼使用了sizeDelta作為大小,但是這個在錨點不重合情況下是不成立的
支援了GridLayout
在啟動時檢查錨點和軸心,友善使用
修複了原代碼在往前拖拽會卡頓的問題
優化代碼,提升性能
支援反向滑動
支援ScrollBar (在無盡模式下不起作用;如果元素大小不一緻會出現滾動條瑕疵)
此外,我修改了Easy Object Pool作為池子,循環利用元素。
警告: 為了解決原始代碼回拉卡頓的問題,我直接複制了一份UGUI中的ScrollRect代碼,而沒有繼承。這是因為老的做法是在onDrag裡停止并立即啟動滾動,而我通過修改兩個私有變量保證了滑動順暢。所有我的代碼都用==========LoopScrollRect==========這樣的注釋包起來,維護起來就像打patch了。
和UGUI自帶的ScrollRect有所不同,我拆分出了LoopHorizontalScrollRect和LoopVerticalScrollRect兩個類,分别代表水準滾動條和水準滾動條。下面我們以LoopVerticalScrollRect為例,水準版本類似。
1. 判定cell大小
LoopScrollRect要解決的核心問題是:如何計算每個元素的大小。這裡我使用了Content Size Fitter配合Layout Element來控制每個cell的長寬,是以對于GridLayout直接取高度,否則取Preferred Height。需要注意的是,除了元素本身的大小之外,我們還要将padding考慮進去。
這個其實也是最核心的一個地方:在能夠準确計算格子大小的基礎上,後續工作就好實作了。
2. 如何優雅的增删元素
對于每個ScrollRect,其實隻需要考慮在頭部和尾部是否需要增加或者删除元素。在這裡以頭部的各種情況為例進行解釋,因為在正向滑動情況下,必須保證在修改元素之後整個ScrollRect内容顯示一緻不跳變;這些情況比尾部處理會麻煩一些。
NewItemAtStart函數實作了在頭部增加一個(或一行,針對GridLayout)元素,并傳回這些元素的高度;DeleteItemAtStart代表删除頭部的一個元素。需要注意的是,在修改頭部元素之後要及時修改content的anchoredPosition,這樣才能保證整個内容區域不會因為多了或者少了一行而産生跳變。
3. 何時需要增删元素
這裡需要有兩個概念viewBounds和contentBounds:前者是指ScrollRect本身的大小,一般也對應Mask;後者是指ScrollRect裡所有cell組成的内容部分的大小。在這個基礎上就簡單了:如果contentBounds的最上面比viewBounds的最上面要低,那麼嘗試在頂部增加元素;如果contentBounds的最上面比viewBounds的最上面高很多,那麼嘗試删除元素。
4. 對象池互動
在建立cell和銷毀cell的時候,使用對象池來避免記憶體碎片;同時這裡使用了SendMessage來向每個cell發送必須的資訊,保證資料的正确性。
5. 滾動條相關
這塊我其實是估算的,根據目前的長度和目前元素個數/總個數按照比例縮放,這個在所有cell大小一緻的情況下是沒有問題的;但是如果大小不一緻我就無法得到精确結果,是以會産生一定抖動。我暫時沒有更好辦法,因為得到的資訊就是不夠用。
6. 其他細節
我主要遇到了兩個坑:
增加或者删除元素之後,有時候需要強行調用Canvas.ForceUpdateCanvases()重新整理下。
注意不要在Build Canvas過程中再次修改元素,進而再次觸發Build Canvas。
以豎直滾動條為例,介紹一下步驟。如果覺得麻煩的話,直接打開DemoScene複制粘貼就好。當然你也可以幹掉EasyObjPool,自己控制生成和銷毀。
1. 準備好Prefabs
每個物體上需要貼上Layout Element并指定preferred width/height。
貼上一個腳本接受void ScrollCellIndex (int idx) 消息,進而對每個位置的元素根據需要靈活修改。
2. 在Hierarchy裡右鍵,選擇UI/Loop Horizontal Scroll Rect或UI/Loop Vertical Scroll Rect即可。使用Component菜單裡的也是一樣的。
Init in Start: 啟動時自動調用Refill cells初始化
Prefab Pool: EasyObjPool物體
Prefab Pool Name: 第二步中對應的Cell Prefab名字
Total Count: 總共能有多少物體,範圍0 ~ TotalCount-1
Threshold: 兩端預留出來的緩存量(像素數)
ReverseDirection: 如果是從下往上或者從右往左拖動,就打開這裡
Clear Cells: 清除已有元素,恢複到未初始化狀态
Refill Cells: 初始化并填充元素
如果是正向滑動,就設定pivot為1;否則設為0并打開ReverseDirection。我強烈建議你試試在播放狀态下修改這些參數。
無盡模式
如果需要無限滾動模式,将totalCount設為負數即可。
原文出處:侑虎科技
本文作者:admin
轉載請與作者聯系,同時請務必标明文章原始出處和原文連結及本聲明。