UniRx第一季學習(四) ------ UGUI事件支援/ReactiveProperty/MVP 實現
課程地址 : http://www.sikiedu.com/course/271
涼鞋大大的,可以的話大家多支援一波~
一.UGUI事件支援
UGUI 增強的原理很簡單,就是對 UnityEvent 提供了 AsObservable ⽅法。
程式碼如下:
public Button mButton;
mButton.onClick.AsObservable().Subscribe(_ => Debug.Log("clicked"));
1.按鈕點選事件
mButton.OnClickAsObservable() .Subscribe(_ => { // do something });
2.Toggle
mToggle.OnValueChangedAsObservable()
.Subscribe(on =>
{
if (on)
{
// do some thing
}
});
同時支援操作符
mButton.OnClickAsObservable()
.First()
.Subscribe(_ =>
{
// do something
});
不⽌如此,還⽀持 EventSystem 的各種 Trigger 接⼝的監聽。
3.Image 的拖拽
mImage.OnBeginDragAsObservable().Subscribe(_=>{}); mImage.OnDragAsObservable().Subscribe(eventArgs=>{}); mImage.OnEndDragAsObservable().Subscribe(_=>{});
4.Event
UnityEvent mEvent;
void Start()
{
mEvent.AsObservable()
.Subscribe(_ =>
{
// process event
});
}
二.響應式屬性ReactiveProperty
可以替代⼀切變數,給變數創造了很多功能。
假如我們想監聽⼀個值是否發⽣了改變。
public int Age { get { ... } set { if (mAge != value) { mAge = value; // send event OnAgeChanged(); // call delegate } } } public void OnAgeChanged() { }
這樣在類的內部,寫⼀次 OnAgeChanged 是沒問題的。但是我想在這個類的外部監聽這個值的改變,
那就要宣告⼀個委託來搞定了。委託的維護成本⽐較低,是可以接受的,直到發現了 UniRx 的ReactiveProperty。就再也不想⽤委託來做這種⼯作了
public class ReactivePropertyExample : MonoBehaviour
{
public IntReactiveProperty Age = new IntReactiveProperty(0);
void Start()
{
Age.Subscribe(age =>
{
Debug.Log("inner received age changed");
});
Age.Value = 10;
}
}
public class PersonView
{
ReactivePropertyExample mReactiveProeprtyExample;
void Init()
{
mReactiveProeprtyExample.Age.Subscribe((age) =>
{
Debug.Log(age);
});
}
}
當任何時候,Age 的值被設定,就會通知所有 Subscribe 的回撥函式。
⽽ Age 可以被 Subscribe 多次的。
並且同樣⽀持 First、Where 等操作符。
三.MVP 實現
MVP 設計模式 : Model-View-(Reactive)Presenter Pattern
在 Ctrl 中,進⾏ Model 和 View 的繫結。Model 的所有屬性都是⽤ ReactiveProperty,然後在 Ctrl 中進⾏訂閱。
通過 View 更改 Model 的屬性值。形成⼀個 View->Ctrl->Model->Ctrl->View 這麼⼀個事件響應環。
參考以下案例,可以看出UniRx可以迎送實現MVC模式:
public class EnemyExample : MonoBehaviour
{
[SerializeField] EnemyModel mEnemy = new EnemyModel(200);
void Start()
{
var attackBtn = transform.Find("Button").GetComponent<Button>();
var HPText = transform.Find("Text").GetComponent<Text>();
attackBtn.OnClickAsObservable()
.Subscribe(_ =>
{
mEnemy.HP.Value -= 99;
});
mEnemy.HP.SubscribeToText(HPText);
mEnemy.IsDead
.Where(isDead => isDead)
.Select(isDead => !isDead)
.SubscribeToInteractable(attackBtn);
}
}
// Model
public class EnemyModel
{
public ReactiveProperty<long> HP;
public IReadOnlyReactiveProperty<bool> IsDead;
public EnemyModel(long initialHP)
{
HP = new ReactiveProperty<long>(initialHP);
IsDead = HP.Select(hp => hp <= 0).ToReactiveProperty();
}
}
在 Unity ⾥,序列化是⼀個很重要的功能,如果不可序列化,則在編輯器上就看不到引數。⽽ReactiveProperty 是泛型的,序列化起來⽐較麻煩。為了解決這個問題,UniRx ⽀持了可序列化的ReactiveProperty 型別,⽐如 Int/LongReactivePropety、Float/DoubleReactiveProperty、StringReactiveProperty、BoolReactiveProperty,還有更多,請參見InspectableReactiveProperty.cs。
如果你需要 [Multiline] 或者[Range] 新增到 ReactiveProperty 上,你可以使⽤MultilineReactivePropertyAttribute 和 RangeReactivePropertyAttribute 替換 Multiline 和 Range。
這些 InspectableReactiveProperties 可以在 inspector ⾯板顯示,並且當他們的值發⽣變化時發出通知,甚⾄在編輯器⾥變化也可以。
這裡提一下MVVM :
MVVM是Model-View-ViewModel的簡寫。它本質上就是MVC 的改進版。MVVM 就是將其中的View 的狀態和行為抽象化,讓我們將檢視 UI 和業務邏輯分開。當然這些事 ViewModel 已經幫我們做了,它可以取出 Model 的資料同時幫忙處理 View 中由於需要展示內容而涉及的業務邏輯。
這裡沒有實現MVVM的原因是Unity 沒有提供 UI 繫結機制,建立⼀個繫結層過於複雜並且會對效能造成影響(使⽤反射)。儘管如此,檢視還是需要更新。Presenters 層知道 View 元件並且能更新它們