1. 程式人生 > >Unity3d UGUI插件之TSTableView

Unity3d UGUI插件之TSTableView

為我 http 狀態改變 可能 alt 除了 復用 高度 dict

  TSTableView是Tacticsoft工作室開發的一款適用於UGUI的列表(Table)插件,設計靈感來源於iOS/Mac的UITableView,提供高復用、高性能的列表,其主要特點是:

  采用MVC模式

  良好的性能和內存占用優化

  復用列表項

  遺憾的是它暫時不支持橫向列表,需要開發者自己擴展,還有就是優化無止境。

首先介紹下TSTableView的使用方法。

技術分享

上圖是TSTableView編輯時的層次結構。TableViewContainer節點掛載Mask(UGUI)組件,同ScrollView(UGUI)一樣用於列表顯示區域的裁剪。TableView節點掛載了TableView組件和ScrollRect(UGUI)組件。TableViewContent節點掛載了VerticalLayoutGroup組件,用於列表項的縱向布局。

TSTableView設計上采用MVC模式,View功能由TableView提供,控制顯示和處理用戶輸入;實現ITableViewDataSource接口的類實現Model功能,提供列表數據;自定義一個Controller組件來控制視圖和通知狀態改變,為TableView設置數據源,需要將它掛載到具體對象上。

技術分享

其中ITableViewDataSource定義如下,它為TableView提供列表項數量、列表項高度、創建列表項接口:

public interface ITableViewDataSource

{

// get the number of rows that a certain table should display

int GetNumberOfRowsForTableView(TableView tableView);

// get the height of a row of a certain cell in the table view

float GetHeightForRowInTableView(TableView tableView, int row);

// create a cell for a certain row in a table view,

// callers should use tableView.GetReusableCell to cache objects.

TableViewCell GetCellForRowInTableView(TableView tableView, int row);

}

除此之外,需要提供列表項預制件,它設計了具體的列表顯示,需要掛載TableViewCell子類組件和LayoutElement組件,以便TableView能夠識別和調用相關接口。

以下是TSTableView運行時的層次結構:

TableViewContent節點下存放所有正在使用的列表項,其中TopContentPlaceHolder和BottomContentHolder提供占位功能,緩存的列表項放在隱藏的ReusableCell節點下。

接下來重點討論TableView的設計原理。

TableView維護一個可見列表項字典和一個緩存列表項字典,可見列表項使用字典(Dictionary)相比列表(List)會占用更多內存空間,但查找、刪除效率更高,其實可以考慮使用鏈表(LinkedList)可能更好一些。緩存列表因為需要支持不同列表項的混排,采用按標識字符串做key的字典,value使用鏈表來串起同類列表項。

private Dictionary<int, TableViewCell> m_visibleCells;

private Dictionary<string, LinkedList<TableViewCell>> m_reusableCells;

TableView層次結構上非常巧妙地設計兩個占位項來動態計算和伸縮占位空間,分別是TopContentPlaceHolder和BottomContentPlaceHolder,它們掛載LayoutElement組件,能夠動態改變占位空間。

技術分享技術分享

   假定當前使用的是一個超長列表。初始狀態下,不需要TopContentPlaceHolder占位隱藏即可,除了視口可見的幾個列表項,其余列表項因為不可見無需在列表中存在,而內容空間空間都由BottomContentPlaceHolder來完成,此時無緩存項。上面是層次結構和布局示意圖。

技術分享技術分享

隨著列表滑動到中間位置,TopContentPlaceHolder和BottomContentPlaceHolder同時可見,它們分別代表視口之上的不可見空間和視口之下的不可見空間。視口中可顯示的列表項數目不預知,因為每個列表項的高度可變,列表項可以是不同類型,所以列表在不同滑動位置,緩存字典中的緩存項數目會動態變化。上面是層次結構和布局示意圖。

技術分享技術分享

當列表項滑動到底部時,底部不需要占位項BottomContentPlaceHolder,頂部占位項TopContentPlaceHolder則會占取視口之外的內容空間。上面是層次結構和布局示意圖。

為了維持可見列表和計算當前上下占位空間的大小,TableView維護了兩個數組。一個是各列表項高度值數組(包含留白),會隨著列表初始化、刪除和添加列表項、列表重建,相對應地重建和修改高度值數組。另一個是各列表項累積高度值數組,記錄各列表項距頂部的高度值,可以用來快速計算並獲取當前視口中可見的列表項。同時使用一個已累積索引變量來記錄已計算累積高度值的索引,這樣可以在需要的時候才去完成累積值計算,得到惰性計算的目的。

public float[] m_rowHeights;

private float[] m_cumulativeRowHeights;

private int m_cleanCumulativeIndex;

TSTableView是一個針對超長列表的小巧插件,其設計上巧妙地利用現有UGUI組件來達到高復用、高性能的列表效果,可以為我們自定義控件提供一些設計上的方法。

  附上:

    開源網址: https://bitbucket.org/tacticsoft/tstableview

Unity3d UGUI插件之TSTableView