Unity应用架构设计(6)——设计动态数据集合ObservableList
什么是 『動態數據集合』 ?簡而言之,就是當集合添加、刪除項目或者重置時,能提供一種通知機制,告訴UI動態更新界面。有經驗的程序員腦海里迸出的第一個詞就是 ObservableCollection。沒錯,它在WPF中盛行其道,通過它開發者可以很方便的達到動態更新界面。要在Unity 3D中使用ObservableCollection還是有些許困難的,因為Mono并不提供ObservableCollection類。但實際上,自己動手去構建一個『動態數據集合』也非難事,核心在于怎樣去傳播通知。這也是本篇博客的主題。
實現自定義的ObservableList
既然核心在于構建通知機制,談到『通知』兩字,最常見的形式就是以委托或者事件形式將消息廣播給監聽者。遺憾的是,.NET中常見的集合數據結構List并不支持事件的通知。所以我在自定義的ObservableList中增加OnAdd,OnRemove,OnInsert事件,當集合添加或者刪除項時,能廣播通知給客戶端UI界面。
以下圖為例,當點擊+時,『以數據驅動界面的形式』,動態的去更新UI界面:
既然要以數據來驅動界面,首先我們需要定義能存放數據的集合,它就是ObservableList,并且是實現了IList 接口:
public class ObservableList<T>:IList<T> {//...省略部分代碼...private List<T> _value=new List<T>();public delegate void AddHandler(T instance);public AddHandler OnAdd;public delegate void InsertHandler(int index,T instance);public InsertHandler OnInsert;public delegate void RemoveHandler(T instance);public RemoveHandler OnRemove;public void Add(T item){_value.Add(item);if (OnAdd != null){OnAdd(item);}}public bool Remove(T item){if (_value.Remove(item)){if (OnRemove != null){OnRemove(item);}return true;}return false;}public void Insert(int index, T item){_value.Insert(index,item);if (OnInsert!=null){OnInsert(index, item);}} }復制代碼可以看到,自定義的ObservableList實現了 IList 接口,并以泛型的形式約束了數據項類型。當添加或者刪除項時,提供了以事件的形式告訴客戶端UI界面 ,作為觀察者的UI可以順勢做出相應的更新。
岔開話題說一下,為什么要用泛型,這是幾天前有同學在群里問的?
- 好處1:可以約束數據項的類型,讓我們不用每時每刻去強轉。比如你往ArrayList中添加了若干數據,因為ArrayList的數據項Item是萬能的object,所以你每次取出來都需要將object轉為你想要的對象,麻煩。
- 好處2:減少運行時錯誤,因為是數據項是object,所以在編譯時你可以將其強轉為任何類型,但萬一這個object實際是Datetime類型,但你強轉為int,編譯時是沒問題的,但一運行就報錯,泛型約束能有效減少這種情況
完善ObservableList
到目前為止,我們自定義的動態數據集合ObservableList是非常好的設計,但唯一不足的事,它不能支持初始化時通知UI界面更新。 『初始化』 這詞可能有點太術語了,我翻譯一下就是一般初始化一個List,我們都是像如下方式進行:
public ObservableList<FaceBox> DataSource = new ObservableList<FaceBox> {new FaceBox{Name = "Eyes",Level = 10,Face = "Avatar201_Face",Badge = new Badge {Icon = "Icon_WeaponRod", ElementColor = "1CB9FFFF"}},new FaceBox{Name = "Jack",Level = 8,Face = "Avatar202_Face",Badge = new Badge {Icon = "Icon_WeaponSpear", ElementColor = "FF5821FF"}} };復制代碼顯然這即沒有觸發OnAdd,也沒有觸發OnRemove等事件,那么初始化或者重置列表時,UI界面還是得不到更新。那我們怎么去解決呢?還記得第一章中BindableProperty嗎?對了,解決方案就是它,對列表的初始化或者重置就是對Value進行改變。而BindableProperty內部提供了對Value值改變的監聽,一旦Value改變了,將消息廣播出去。
OK,我們增強一下ObservableList:
public class ObservableList<T>:IList<T> {//省略部分代碼...public delegate void ValueChangedHandler(List<T> oldValue, List<T> newValue);public ValueChangedHandler OnValueChanged;//預先初始化,內置的List,防止空異常private List<T> _value=new List<T>();public List<T> Value{get { return _value; }set{if (!Equals(_value, value)){var old = _value;_value = value;ValueChanged(old, _value);}}}private void ValueChanged(List<T> oldValue, List<T> newValue){if (OnValueChanged != null){OnValueChanged(oldValue, newValue);}}}復制代碼所以客戶端UI界面只要對ObservableList的OnValueChanged事件進行監聽,當初始化或者重置時,你也可以得到更新,演示效果如下:
小結
自定義的動態數據集合ObservableList看起來小巧,但五臟俱全,能提供通知機制,可以動態的去更新UI界面。 所有的一切都以數據的改變來驅動UI,這是非常重要的轉變。所以看似代碼復雜了,但實際上你只要關心數據即可。
源代碼托管在Github上,點擊此了解
歡迎關注我的公眾號:
總結
以上是生活随笔為你收集整理的Unity应用架构设计(6)——设计动态数据集合ObservableList的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux 启动流详解
- 下一篇: 《A Novel Pipeline Ap