Unity3d UGUI插件之TSTableView
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