1. 程式人生 > >UniRx第一季學習(四) ------ UGUI事件支援/ReactiveProperty/MVP 實現

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 元件並且能更新它們