UniRx_UniTask_学习记录_3.2_ReactiveProperty

3.2 ReactiveProperty

​ ReactiveProperty 的值可以读写,并且在值变化时发行消息。即带有Observable功能的变数。

3.2.1 ReactiveProperty

​ 值变化时发行OnNext消息。

​ Dispose()执行时,发行OnCompleted消息

  • 基本使用例
using UniRx;
using UnityEngine;

namespace Sample.Section3.ReactiveProperty
{
    public class ReactivePropertySample : MonoBehaviour
    {
        private void Start()
        {
            // int 型的ReactiveProperty
            // 初期値是100  
            var health = new ReactiveProperty<int>(100);
            // .Value 读取现在设定的值
            Debug.Log("現在の値:" + health.Value);
            // ReactiveProperty 可以直接被 Subscribe
            // Subscribe 时 会发行当前设定的值的消息
            health.Subscribe(
                x => Debug.Log("现在通知值:" + x),
                () => Debug.Log("OnCompleted"));
            // .Value 赋值时 、发行OnNext 消息
            health.Value = 50;
            Debug.Log("现在的值:" + health.Value);
            // Dispose()时发行 OnCompleted 消息
            health.Dispose();
        }
    }
}

像这样每当ReactiveProperty 的Value属性更新时,发行OnNext消息

ReactiveProperty 的Value属性可以被读取,读取时是当时最新的值

  • 强制发行消息

    ReactiveProperty 的Value属性更新时,如果更新的值和上一个值相同,不会发行消息,如果想要强制将值发行需要使用SetValueAndForceNotify()

    using UnityEngine;
    using UniRx;
    
    namespace Sample.Section3.ReactiveProperty
    {
        public class ReactivePropertySample2 : MonoBehaviour
        {
            private void Start()
            {
                var health = new ReactiveProperty<int>(100);
                health
                    .Subscribe(x => Debug.Log("通知的值:" + x));
                // x
                Debug.Log("<Value = 100>");
                health.Value = 100;
                // 强制发行消息使用SetValueAndForceNotify
                Debug.Log("<Value 强制更新>");
                health.SetValueAndForceNotify(100);
    
                health.Dispose();
            }
        }
    }
    
  • 跳过想要发行的消息

    当不想要发行某消息时 可以使用SkipLatestValueOnSubscribe()

    using UnityEngine;
    using UniRx;
    
    namespace Sample.Section3.ReactiveProperty
    {
        public class ReactivePropertySample3 : MonoBehaviour
        {
            private void Start()
            {
                var health = new ReactiveProperty<int>(100);
                health
                    // Subscribe()后的无视OnNext消息
                    .SkipLatestValueOnSubscribe()
                    .Subscribe(x => Debug.Log("通知的值:" + x));
    
                health.Value = 50;
                health.Dispose();
            }
        }
    }
    
  • ReactiveProperty 的值在编辑器上设定

    ReactiveProperty 不能在编辑器上设定值,如果想要设定,可以只用类型明确的IntReactiveProperty 的类型

    using UnityEngine;
    using UniRx;
    
    namespace Sample.Section3.ReactiveProperty
    {
        public class ReactivePropertyOnInspectorWindow : MonoBehaviour
        {
            // 不会表示
            public ReactiveProperty<int> A;
            // 会表示
            public IntReactiveProperty B;
            
            //其他的各种类型
            public LongReactiveProperty C1;
            public ByteReactiveProperty C2;
            public FloatReactiveProperty C3;
            public DoubleReactiveProperty C4;
            public StringReactiveProperty C5;
            public BoolReactiveProperty C6;
            public Vector2ReactiveProperty C7;
            public Vector3ReactiveProperty C8;
            public Vector4ReactiveProperty C9;
            public ColorReactiveProperty C10;
            public RectReactiveProperty C11;
            public AnimationCurveReactiveProperty C12;
            public BoundsReactiveProperty C13;
            public QuaternionReactiveProperty C14;
        }
    }
    

    想使用以上类型以外的情况,需要自己对其定义

  • 使用ReactiveProperty 的自定义类,在编辑器上设定

    using System;
    using UniRx;
    
    namespace Sample.Section3.ReactiveProperty
    {
        // Fruit Enum
        public enum Fruit
        {
            Apple,
            Banana,
            Peach,
            Melon,
            Orange
        }
        // Fruit 型的 ReactiveProperty
        [Serializable]
        public class FruitReactiveProperty : ReactiveProperty<Fruit>
        {
            public FruitReactiveProperty()
            {
            }
            public FruitReactiveProperty(Fruit init) : base(init)
            {
            }
        }
        
    }
    

    但是这样并不会在编辑器上显示,需要进行编辑器扩张

    using UniRx;
    
    namespace Sample.Section3.ReactiveProperty.Editor
    {
        // 编辑器扩张
        [UnityEditor.CustomPropertyDrawer(typeof(FruitReactiveProperty))]
        public class ExtendInspectorDisplayDrawer : InspectorDisplayDrawer
        {
        }
    }
    

    这样就可以在编辑器上 定义了

3.2.2 ReadOnlyReactiveProperty

读取专用的ReactiveProperty,不能写

  • 使用例

    using UniRx;
    using UnityEngine;
    
    namespace Sample.Section3.ReactiveProperty
    {
        public class ReadOnlyReactivePropertySample : MonoBehaviour
        {
            private void Start()
            {
                //Int型的 ReactiveProperty
                var intReactiveProperty =
                    new ReactiveProperty<int>(100);
                
                // int型的 ReadOnlyReactiveProperty
                var readOnlyInt = 
                    // ReactiveProperty 变换成 ReadOnlyReactiveProperty
                    intReactiveProperty.ToReadOnlyReactiveProperty();
                
                // 可读
                Debug.Log("现在的值:" + readOnlyInt.Value);
                //可以订阅
                readOnlyInt.Subscribe(x => Debug.Log("通知的值 :" + x));
                // 不可写
                // readOnlyInt.Value = 10;
                intReactiveProperty.Dispose();
            }
        }
    }
    
  • IReadOnlyReactiveProperty

    IReadOnlyReactiveProperty这个接口定义了 ReadOnlyReactiveProperty 的行为

    namespace UniRx
    {
        public interface IReadOnlyReactiveProperty<T> : IObservable<T>
        {
            T Value { get; }
            bool HasValue { get; }
        }
    }
    

​ ReactiveProperty 继承了 IReadOnlyReactiveProperty ,所有 ReactiveProperty 可以 转换成 ReadOnlyReactiveProperty

using System.Collections;
using UniRx;
using UnityEngine;

namespace Sample.Section3.ReactiveProperty
{
    //倒计时
    public class ReactivePropertyTimerSample : MonoBehaviour
    {
        // 定义 ReactiveProperty 
        [SerializeField]
        private IntReactiveProperty _current = new IntReactiveProperty(60);
        // 现在的倒计时的时间 (读取专用)
        // ReactiveProperty 转换成 IReadOnlyReactiveProperty
        public IReadOnlyReactiveProperty<int> CurrentTime => _current;
        
        // 
        private void Start()
        {
            StartCoroutine(CountDownCoroutine());
            _current
                .Subscribe(_x =>
                {
                    Debug.Log($"倒计时 {_x}");
                }).AddTo(this);
        }
        private IEnumerator CountDownCoroutine()
        {
            while (_current.Value > 0)
            {
                // 1秒 更新 1此
                _current.Value--;
                yield return new WaitForSeconds(1);
            }
        }
    }
}

3.2.3 ReactiveCollection

ReactiveCollection 对 List 最佳发行消息功能。

• ObserveAdd :要素添加
• ObserveRemove :要素删除
• ObserveReplace : 要素变更
• ObserveCountChanged:要素总数变更
• ObserveMove :要素索引变更
• ObserveReset :List Clear

使用例

using UniRx;
using UnityEngine;

namespace Sample.Section3.ReactiveProperty
{
    public class ReactiveCollectionSample : MonoBehaviour
    {
        private void Start()
        {
            var rc = new ReactiveCollection<int>();
            
            //订阅 要素增加的消息 
            rc.ObserveAdd()
                .Subscribe((CollectionAddEvent<int> a) =>
                {
                    Debug.Log($"Add [{a.Index}]:{a.Value}");
                });
            //订阅 要素删除的消息 
            rc.ObserveRemove()
                .Subscribe((CollectionRemoveEvent<int> r) =>
                {
                    Debug.Log($"Remove [{r.Index}]:{r.Value}");
                });
            // 订阅 要素更新 的消息
            rc.ObserveReplace()
                .Subscribe((CollectionReplaceEvent<int> r) =>
                {
                    Debug.Log($"Replace [{r.Index}]:{r.OldValue} -> {r.NewValue}");
                });

            // 订阅 要素个数更新 的消息
            rc.ObserveCountChanged()
                .Subscribe((int c) =>
                {
                    Debug.Log($"Count: {c}");
                });

            // 订阅 要素的Index 变更的消息
            rc.ObserveMove()
                .Subscribe((CollectionMoveEvent<int> x) =>
                {
                    Debug.Log($"Move {x.Value}:[{x.OldIndex}] -> [{x.NewIndex}]");
                });
   
            rc.Add(1);
            rc.Add(2);
            rc.Add(3);
            rc[1] = 5;
            rc.RemoveAt(0);
            // Dispose() 时候向 Observable 发送 OnCompleted的消息  
            rc.Dispose();
        }
    }
}

3.2.4 ReactiveDictionary<TKey, TValue>

ReactiveDictionary<TKey, TValue> 对 Dictionary<TKey, TValue> 增加 消息发送机能

• ObserveAdd :添加新的Key
• ObserveRemove :删除新的Key
• ObserveReplace :key的值变更
• ObserveCountChanged:要素总数的变更
• ObserveReset :Dictionary Clear()

using System;
using UniRx;
using Unity.VisualScripting;
using UnityEngine;

namespace Sample.Section3.ReactiveProperty
{
    public class ReactiveDictionarySample : MonoBehaviour
    {
        private void Start()
        {
                var rd = new ReactiveDictionary<string, string>();
                // 订阅 要素添加的消息
                rd.ObserveAdd()
                    .Subscribe((DictionaryAddEvent<string, string> a) =>
                    {
                        Debug.Log($"[{a.Key}]里添加{a.Value}");
                    });
                // 订阅 要素消除的消息
                rd.ObserveRemove()
                    .Subscribe((DictionaryRemoveEvent<string, string> r) =>
                    {
                        Debug.Log($"[{r.Key}]里消除{r.Value}");
                    });
                // 订阅 要素更新的消息
                rd.ObserveReplace()
                    .Subscribe((DictionaryReplaceEvent<string, string> r) =>
                    {
                        Debug.Log($"[{r.Key}]的{r.OldValue}更新成{r.NewValue}");
                    });
                // 订阅 要素总数更新的消息
                rd.ObserveCountChanged()
                    .Subscribe((int c) =>
                    {
                        Debug.Log("要素总数" + c);
                    });
                // Add
                rd["Apple"] = "苹果";
                rd["Banana"] = "香蕉";
                rd["Lemon"] = "柠檬";
                // Replace
                rd["Apple"] = "红苹果";
                // Remove
                rd.Remove("Banana");
                // Dispose() 时候向 Observable 发送 OnCompleted的消息  
                rd.Dispose();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值