【Unity 插件推薦】LoopScrollRect 滾動高手,流暢實現無限內容加載!

目錄
【Unity 插件推薦】LoopScrollRect 滾動高手,流暢實現無限內容加載!

 

前言

 

今天要推薦的是 UnityLoopScrollRect 插件,一款專為【無限滾動列表】與【高效內容加載】需求設計的強大工具,能夠幫助開發者輕鬆應對大數據列表顯示的挑戰!不僅支持靈活的【動態內容更新】、【節省內存】,還提供直觀的【滾動加載邏輯設計】,無論是【玩家排行榜】、【商品列表】,還是【社交動態流】,LoopScrollRect 都能高效解決你的開發需求。

本篇文章將帶你深入了解如何快速上手 LoopScrollRect 插件,包含【設置滾動列表】、【實現無縫數據加載】以及【優化內存性能】的技巧,整篇文章包括對插件的【詳細介紹】與【補充說明】,幫助開發者在大數據場景中流暢呈現內容,避免常見問題,提升用戶體驗!如果你正在尋找能實現流暢無縫滾動的利器,千萬不要錯過 LoopScrollRect 這個插件!

今天要推薦的是 Unity 的 LoopScrollRect 插件,一款專為【無限滾動列表】與【高效內容加載】需求設計的強大工具,能夠幫助開發者輕鬆應對大數據列表顯示的挑戰!不僅支持靈活的【動態內容更新】、【節省內存】,還提供直觀的【滾動加載邏輯設計】,無論是【玩家排行榜】、【商品列表】,還是【社交動態流】,LoopScrollRect 都能高效解決你的開發需求。  本篇文章將帶你深入了解如何快速上手 LoopScrollRect 插件,包含【設置滾動列表】、【實現無縫數據加載】以及【優化內存性能】的技巧,整篇文章包括對插件的【詳細介紹】與【補充說明】,幫助開發者在大數據場景中流暢呈現內容,避免常見問題,提升用戶體驗!如果你正在尋找能實現流暢無縫滾動的利器,千萬不要錯過 LoopScrollRect 這個插件!

 

 

Unity LoopScrollRect 插件介紹


LoopScrollRect 是一款專為 Unity 設計的高效滾動內容管理插件,它通過【循環滾動】與【數據加載】的創新方式,大幅減少  UI 元素內存占用,實現大數據場景下的流暢滾動與無縫內容顯示,無論是【玩家排行榜】、【商品展示列表】,還是【社交訊息顯示】,LoopScrollRect 這個插件都能提供穩定且高效的解決方案,是 Unity 開發者不可或缺的 UI 工具。

LoopScrollRect 是一款專為 Unity 設計的高效滾動內容管理插件,它通過【循環滾動】與【數據加載】的創新方式,大幅減少  UI 元素內存占用,實現大數據場景下的流暢滾動與無縫內容顯示,無論是【玩家排行榜】、【商品展示列表】,還是【社交訊息顯示】,LoopScrollRect 這個插件都能提供穩定且高效的解決方案,是 Unity 開發者不可或缺的 UI 工具。

 

功能特色

  1. 動態內容加載能力
    支持【動態生成】與【釋放 UI 元素】,只渲染當前可見的內容,顯著降低內存佔用,適合有大量數據的場景。
  2. 靈活的滾動行為控制
    支持【垂直】或【水平】滾動,並兼容各種 UI 布局,提供自定義【滾動速度】、【緩動效果】與【內容定位】功能。
  3. 高效性能優化
    針對 Unity 進行性能調校,在保持流暢滾動的同時,確保 UI 元素高效【加載】與【釋放】,提升用戶體驗。

 

適用場景

  1. 玩家排行榜顯示
    在多人遊戲中實現即時更新的排行榜,無需載入整個列表即可顯示數百甚至上千名玩家的數據。
  2. 商品展示列表
    適合【遊戲商城】或【資源管理】等應用,支持無限滾動並顯示動態加載的商品信息,實現流暢的購物體驗。
  3. 動態訊息顯示
    在遊戲大廳中實現消息滾動顯示功能,支持【即時內容更新】與【循環滾動】的設計,提升用戶的【互動體驗】與【資訊接收效率】。
【Unity 插件推薦】LoopScrollRect 滾動高手,流暢實現無限內容加載!


 

Unity LoopScrollRect 外掛

 

插件可以通過 github 進行下載,鏈接:

GitHub 下載連結:LoopScrollRect

 

 

Unity LoopScrollRect 插件作者文檔解讀

 

插件作者在忙於性能優化時,深切體會到二八法則真是指導高 (tou) 效 (lan) 工作的強大武器。在某個禮拜花了幾天解決了一個實際問題:UGUIScrollRect 加載太多物體的時候,第一次彈出界面會非常卡頓,而且不在界面裡的內容依然會參與繪製(毫無意義的浪費…) 。

 

變更日誌

  • v1.03 終於支援了 ScrollBar,支援直接創建。
  • v1.02 Bug Fixes,無盡模式。
  • v1.01 重構了好幾遍,基本算重寫了份…優化了拖曳手感和回收部分的計算,增加了反方向滑動支援。升級至 Unity 5.2 的 UGUI API。
  • v1.0 這兩天基於網上找的一份 InfinityScroll 代碼,把這個功能做了。在加載時間和 Draw Call 上都提升顯著,而且滑動的時候也沒有卡頓。

每個元素知道自己的序號,可以依需求修改自己的內容、大小等資訊。

此外支援了 ScrollBar,支援橫向、縱向及正反向。

在關閉 Mask 後可以看到,只有在需要的時候才動態實例化元素,使用完後再回收。

 

介紹

最原始版本的程式碼是 @ivomarel 的 InfinityScroll。插件作者改到後來,基本上和原文版沒啥相同的了…

  • 原始碼使用了 sizeDelta 作為大小,但是這個在錨點不重合情況下是不成立的。
  • 支持了 GridLayout。
  • 啟動時檢查錨點和軸心,方便使用。
  • 修正了原代碼在往前拖曳會卡頓的問題。
  • 優化程式碼,提升效能。
  • 支援反向滑動。
  • 支援 ScrollBar (在無盡模式下不起作用; 如果元素大小不一致會出現捲軸瑕疵)。

另外,插件作者修改了 Easy Object Pool 作為池子,循環利用元素。

警告: 為了解決原始程式碼回拉卡頓的問題,插件作者直接複製了一份 UGUI 中的 ScrollRect 程式碼,而沒有繼承。這是因為老的做法是在 onDrag 裡面停止並立即啟動滾動,而插件作者透過修改兩個私有變數保證了滑動順暢。所有作者的程式碼都用 ==========LoopScrollRect========== 這樣的註解包起來,維護起來就像打 patch了…。

 

框架思路

和 UGUI 自帶的 ScrollRect 有所不同,插件作者拆分出了 LoopHorizontalScrollRectLoopVerticalScrollRect 兩個類,分別代表水平滾動條和水平滾動條。下面插件作者以 LoopVerticalScrollRect 為例,水平版類似。

protected override float GetSize(RectTransform item)

{

    float size = contentSpacing;

    if (m_GridLayout != null)

    {

        size += m_GridLayout.cellSize.y;

    }

    else

    {

        size += LayoutUtility.GetPreferredHeight(item);

    }

    return size;

}

這個其實也是最核心的一個地方:在能夠準確計算格子大小的基礎上,後續工作就好實現了。

 

如何優雅的增刪元素

對於每個 ScrollRect,其實只需要考慮在頭部和尾部是否需要增加或刪除元素。這裡以頭部的各種情況為例進行解釋,因為在正向滑動情況下,必須保證在修改元素之後整個 ScrollRect 內容顯示一致不跳變;這些情況比尾部處理會麻煩一些。

 NewItemAtStart 函數實作了在頭部增加一個(或一行,針對 GridLayout)元素,並傳回這些元素的高度;DeleteItemAtStart 代表刪除頭部的一個元素。需要注意的是,在修改頭部元素之後要及時修改 contentanchoredPosition,這樣才能確保整個內容區域不會因為多了或少了一行而產生跳變。

protected float NewItemAtStart()

{

    float size = 0;

    for (int i = 0; i < contentConstraintCount; i++)

    {

        // Get Element from ObjectPool

    }

    if (!reverseDirection)

    {

        // Modify content.anchoredPosition

    }

    return size;

}

protected float DeleteItemAtStart()

{

    float size = 0;

    for (int i = 0; i < contentConstraintCount; i++)

    {

        // Return Element to ObjectPool

    }

    if (!reverseDirection)

    {

        // Modify content.anchoredPosition

    }

    return size;

}

 

何時需要增刪元素

這裡需要有兩個概念 viewBoundscontentBounds :前者是指 ScrollRect 本身的大小,一般也對應 Mask;後者是指 ScrollRect 裡所有 cell 組成的內容部分的大小。在這個基礎上就簡單了:如果 contentBounds 的最上面比 viewBounds 的最上面要低,那麼嘗試在頂部增加元素;如果 contentBounds 的最上面比 viewBounds 的最上面高很多,那麼嘗試刪除元素。

protected override bool UpdateItems(Bounds viewBounds, Bounds contentBounds)

{

    bool changed = false;

    // cases for NewItemAtEnd/DeleteItemAtEnd

    if (viewBounds.max.y > contentBounds.max.y - 1)

    {

        float size = NewItemAtStart();

        if (size > 0)

        {

            changed = true;

        }

    }

    else if (viewBounds.max.y < contentBounds.max.y - threshold)

    {

        float size = DeleteItemAtStart();

        if (size > 0)

        {

            changed = true;

        }

    }

    return changed;

}

 

物件池交互

在新建 cell 和銷毀 cell 的時候,使用物件池來避免記憶體碎片;同時這裡使用了 SendMessage 來向每個 cell 發送必須的訊息,保證資料的正確性。

private void SendMessageToNewObject(Transform go, int idx)

{

    go.SendMessage("ScrollCellIndex", idx);

}

private void ReturnObjectAndSendMessage(Transform go)

{

    go.SendMessage("ScrollCellReturn", SendMessageOptions.DontRequireReceiver);

    prefabPool.ReturnObjectToPool(go.gameObject);

}

private RectTransform InstantiateNextItem(int itemIdx)

{

    RectTransform nextItem = prefabPool.GetObjectFromPool(prefabPoolName).GetComponent<RectTransform>();

    nextItem.transform.SetParent(content, false);

    nextItem.gameObject.SetActive(true);

    SendMessageToNewObject(nextItem, itemIdx);

    return nextItem;

}

 

捲軸相關

這塊插件作者其實是估算的,根據當前的長度和當前元素個數/總個數按照比例縮放,這個在所有 cell 大小一致的情況下是沒有問題的;但是如果大小不一致我就無法得到精確結果,所以會產生一定抖動。插件作者暫時沒有更好辦法,因為得到的資訊就是不夠用…。

 

其他細節

插件作者主要遇到了兩個坑:

  • 增加或刪除元素之後,有時候需要強制呼叫 Canvas.ForceUpdateCanvases() 刷新下。
  • 注意不要在 Build Canvas 過程中再次修改元素,從而再次觸發 Build Canvas…。

 

使用範例

以垂直滾動條為例,介紹一下步驟。如果覺得麻煩的話,直接打開 DemoScene 複製貼上就好,當然也可以幹掉 EasyObjPool,自己控制生成和銷毀。

  • 準備好 Prefabs
    • 每個物體上需要貼上 Layout Element 並指定 preferred width/height。
    • 貼上腳本接受 void ScrollCellIndex (int idx) 訊息,從而對每個位置的元素根據需要靈活修改。
  • 在 Hierarchy 裡右鍵,選擇 UI/Loop Horizo​​ntal 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 設為負數即可。

 

他人工作

後來插件作者搜了下,發現網路上也有人提到 UGUI ScrollRect 優化,不過他的策略是監聽 ScrollRect 的 value,然後停用範圍外的 cell。最後 UGUI ScrollRect 優化的作者也提到改成動態載入策略。這種基於 value 的做法我不太確認在滾動前動態添加新元素的時候是否會出現問題。

 

 

Unity LoopScrollRect 導入插件

 

把這個連結複製到 Package Manager 中進行中進行導入:

https://github.com/qiankanglai/LoopScrollRect. git

把這個連結複製到 Package Manager 中進行中進行導入:  https://github.com/qiankanglai/LoopScrollRect. git

 

 

Unity LoopScrollRect 查看案例

 

如果你導入插件成功,點擊 DemoScene 進入演示場景,找到多行多列,上下滾動的案例。

如果你導入插件成功,點擊 DemoScene 進入演示場景,找到多行多列,上下滾動的案例。
如果你導入插件成功,點擊 DemoScene 進入演示場景,找到多行多列,上下滾動的案例。

 

 

Unity LoopScrollRect 使用

 

可以在 Inspector 中看到他身上掛著一個腳本。

可以在 Inspector 中看到他身上掛著一個腳本:

這個腳本就是用來初始化滾動容器的核心,我們新建立一個自己的腳本,把 InitOnStart 中的程式碼抄過來,然後改成自己的,我命名為:PackageScroll.cs。

腳本中的幾個要點:

  1. Start 函數中對 LoopScrollRect 進行初始化,唯一需要修改的是 ls.totalCount,改成自己的物品總量即可。
  2. ProvideData:實作 LoopScrollDataSource 接口,子物件從這裡拿到資料來刷新自身
  3. 其他可以保持案例中的程式碼不變,GetObject 和 ReturnObject 實作了一個類似物件池的快取功能。

 

using UnityEngine;

using System.Collections.Generic;

using UnityEngine.UI;

namespace Demo

{

   [RequireComponent(typeof(UnityEngine.UI.LoopScrollRect))]

   [DisallowMultipleComponent]

   public class PackageScroll : MonoBehaviour, LoopScrollPrefabSource, LoopScrollDataSource

   {

       public GameObject item;

       public int totalCount = -1;

       // Implement your own Cache Pool here. The following is just for example.

       Stack<Transform> pool = new Stack<Transform>();

       public GameObject GetObject(int index)

       {

           if (pool.Count == 0)

           {

               return Instantiate(item);

           }

           Transform candidate = pool.Pop();

           candidate.gameObject.SetActive(true);

           return candidate.gameObject;

       }

       public void ReturnObject(Transform trans)

       {

           // Use `DestroyImmediate` here if you don't need Pool

           trans.SendMessage("ScrollCellReturn", SendMessageOptions.DontRequireReceiver);

           trans.gameObject.SetActive(false);

           trans.SetParent(transform, false);

           pool.Push(trans);

       }

       public void ProvideData(Transform transform, int idx)

       {

           List<PackageLocalItem> items = GameManager.Instance.GetSortPackageLocalData();

           PackagePanel uiParent = (PackagePanel)UIManager.Instance.GetPanel(UIConst.PackagePanel);

           transform.GetComponent<PackageCell>().Refresh(items[idx], uiParent);

       }

       void Start()

       {

           var ls = GetComponent<LoopScrollRect>();

           ls.prefabSource = this;

           ls.dataSource = this;

           ls.totalCount = GameManager.Instance.GetSortPackageLocalData().Count;

           ls.RefillCells();

       }

   }

}


然後把這個腳本掛到 VerticalScroll_Grid 物件身上,把原本 demo 中的 InitOnStart 腳本刪了。

因為咱們的背包介面是從預製件中動態創建的,因此需要把 VerticalScroll_Grid 拷貝到 PackagePanel 中(替換原本的 ScrollView)

因為咱們的背包介面是從預製件中動態創建的,因此需要把 VerticalScroll_Grid 拷貝到 PackagePanel 中(替換原本的 ScrollView)

PackagePanel.cs 是背包系統介面的主要程式碼,這裡咱們把對原版 scrollView 初始化的邏輯註解掉,這樣之前的滾動容器就相當於失效了。

PackagePanel.cs 是背包系統介面的主要程式碼,這裡咱們把對原版 scrollView 初始化的邏輯註解掉,這樣之前的滾動容器就相當於失效了。

 

最後解決第二個問題,根據官方文檔,子物體需要做下小小的調整。

加上 Layout Element 這個組件,用來控制子物體的大小,其他都不用改。

加上 Layout Element 這個組件,用來控制子物體的大小,其他都不用改。

 

這時候運行遊戲就可以看到,我們專案中的滾動容器已經替換為 LoopScrollView。

這時候運行遊戲就可以看到,我們專案中的滾動容器已經替換為 LoopScrollView。

 

一些大小和間距可以在這裡調整

外層容器的大小:

外層容器的大小:

 

內層容器的大小:

內層容器的大小:

 

 

Unity LoopScrollRect 相關介紹 & 教學影片

 

 

 

Unity LoopScrollRect 滾動高手大師相關網站 & 插件下載點

 

【LoopScrollRect】

GitHub 下載連結:LoopScrollRect

qiankanglai.me 插件作者個人部落格:优化 UGUI 的 ScrollRect

————————————————

以上內容改編節錄自:

qiankanglai.me  作者:Kanglai Qian 

CSDN 作者:向宇it

 

更多好用插件:【Unity 好用插件推薦】持續更新,一起讓遊戲開發事半功倍!

 

 

 

本文原創(或整理)於亞洲電玩通,未經作者與本站同意不得隨意引用、轉載、改編或截錄。

特約作家簡介

X
A
Y
B
JamXu的頭像
JamXu
十年遊戲研發
二十年遊戲台主
三十年遊戲玩家

經中華網龍遊戲企劃進入遊戲圈,然後被雷打到去學程式前後端又學了點設計帶帶幾個研發團隊,見證了 3D 渲染技術及遊戲引擎互相進步,也見證了研發代理的更迭與博弈遊戲的興起,再毅然研究起 SEO 網路行銷社群廣告投放,深信自研自賣才是最大贏家,期望能為台灣研發重回輝煌時光貢獻一點力量。如果你也有遊戲夢,歡迎交流認識。


支持贊助 / DONATE

 

亞洲電玩通只是很小的力量,但仍希望為復甦台灣遊戲研發貢獻一點動能,如果您喜歡亞洲電玩通的文章,或是覺得它們對您有幫助,歡迎給予一些支持鼓勵,不論是按讚追蹤或是贊助,讓亞洲電玩通持續產出,感謝。

亞洲電玩通AsiaGameMaster - Steam 遊戲鑑賞家
亞洲電玩通AsiaGameMaster - FB 粉絲專頁
亞洲電玩通AsiaGameMaster - IG 粉絲專頁
亞洲電玩通AsiaGameMaster - Twitter
亞洲電玩通AsiaGameMaster - Yoytube 粉絲專頁
亞洲電玩通AsiaGameMaster - Tiktok

BTC

亞洲電玩通AsiaGameMaster - BTC 鏈贊助地址

352Bw8r46rfXv6jno8qt9Bc3xx6ptTcPze

 

ETH

亞洲電玩通AsiaGameMaster - ETH 鏈贊助地址

0x795442E321a953363a442C76d39f3fbf9b6bC666

 

TRON

亞洲電玩通AsiaGameMaster - TRON 鏈贊助地址

TCNcVmin18LbnXfdWZsY5pzcFvYe1MoD6f

延伸閱讀