MVVM框架在unity開發中的使用


1、什么是MVVM

借用一下百度百科上對MVVM的介紹,MVVM是Model-View-ViewModel的簡寫,它本質上就是MVC 的改進版。MVVM 就是將其中的View 的狀態和行為抽象化,讓我們將視圖 UI 和業務邏輯分開。當然這些事 ViewModel 已經幫我們做了,它可以取出 Model 的數據同時幫忙處理 View 中由於需要展示內容而涉及的業務邏輯。
 

2、MVVM在unity開發中的應用

MVVM框架應用面十分廣泛,通常在前端開發中應用很廣,最近看到周圍同事在開發WPF時用到了這個框架,抱着好奇的態度來學習一下這個框架,MVVM框架在unity開發中同樣適用,在unity中,將每個UI抽象成一個個View,通常我們為每一個UI面板定義一個View,View中包含了該面板中涉及到的UI元素,比如一個Text,一個Button;每一個View都有獨立的ViewModel來管理,ViewModel中提供必要的屬性和方法來控制View, 而Model只是單純的定義一個數據模型。前兩天在github上發現了這個叫uMVVM的框架,拿來試用了一下,下面分析一下該框架對MVVM模式的設計。
 

3、uMVVM的設計與實現

下載uMVVM后,它提供了一些使用示例:

在這個示例中,有兩個panel,就定義了兩個view,每個view中定義該界面的元素,比如SetupView:

public class SetupView:UnityGuiView<SetupViewModel>
    {

        public InputField nameInputField;
        public Text nameMessageText;

        public InputField jobInputField;
        public Text jobMessageText;

        public InputField atkInputField;
        public Text atkMessageText;

        public Slider successRateSlider;
        public Text successRateMessageText;

        public Toggle joinToggle;
        public Button joinInButton;
        public Button waitButton;
        
        public SetupViewModel ViewModel { get { return (SetupViewModel)BindingContext; } }

        }
可以看到,View中需要指定對應的ViewModel來管理該View,ViewModel中定義的屬性需要具備當數據改變時通知訂閱者的功能,因此uMVVM對這種屬性進行了一層封裝,具體設計如下:

public class BindableProperty<T>
    {
        public delegate void ValueChangedHandler(T oldValue, T newValue);

        public ValueChangedHandler OnValueChanged;

        private T _value;
        public T Value
        {
            get
            {
                return _value;
            }
            set
            {
                if (!Equals(_value, value))
                {
                    T old = _value;
                    _value = value;
                    ValueChanged(old, _value);
                }
            }
        }

        private void ValueChanged(T oldValue, T newValue)
        {
            if (OnValueChanged != null)
            {
                OnValueChanged(oldValue, newValue);
            }
        }

        public override string ToString()
        {
            return (Value != null ? Value.ToString() : "null");
        }
    }
可以看到,BindableProperty類中維護一個T類型數據,當T發生變化時,可以通知到訂閱者,有了這種屬性之后,那么ViewModel就是這樣的了:

public class SetupViewModel:ViewModelBase
    {
        public readonly BindableProperty<string> Name = new BindableProperty<string>();
        public readonly BindableProperty<string> Job=new BindableProperty<string>(); 
        public readonly BindableProperty<int> ATK = new BindableProperty<int>();
        public readonly BindableProperty<float> SuccessRate=new BindableProperty<float>(); 
        public readonly BindableProperty<State> State=new BindableProperty<State>();
}
uMVVM的設計中,每個View都繼承UnityGuiView這個泛型類,UnityGuiView大概的內容是這樣:

public abstract class UnityGuiView<T>:MonoBehaviour,IView<T> where T:ViewModelBase
    {
        private bool _isInitialized;
        public bool destroyOnHide;
        protected readonly PropertyBinder<T> Binder=new PropertyBinder<T>();
        public readonly BindableProperty<T> ViewModelProperty = new BindableProperty<T>();
 
        public T BindingContext
        {
            get { return ViewModelProperty.Value; }
            set
            {
                if (!_isInitialized)
                {
                    OnInitialize();
                    _isInitialized = true;
                }
                //觸發OnValueChanged事件
                ViewModelProperty.Value = value;
            }
        }

        /// <summary>
        /// 初始化View,當BindingContext改變時執行
        /// </summary>
        protected virtual void OnInitialize()
        {
            //無所ViewModel的Value怎樣變化,只對OnValueChanged事件監聽(綁定)一次
            ViewModelProperty.OnValueChanged += OnBindingContextChanged;
        }
        
        /// <summary>
        /// 當gameObject將被銷毀時,這個方法被調用
        /// </summary>
        public virtual void OnDestroy()
        {
            if (BindingContext.IsRevealed)
            {
                Hide(true);
            }
            BindingContext.OnDestory();
            BindingContext = null;
            ViewModelProperty.OnValueChanged = null;
        }

        /// <summary>
        /// 綁定的上下文發生改變時的響應方法
        /// 利用反射+=/-=OnValuePropertyChanged
        /// </summary>
        public virtual void OnBindingContextChanged(T oldValue, T newValue)
        {
            Binder.Unbind(oldValue);
            Binder.Bind(newValue);
        }
    }
UnityGuiView中有一個BindingContext的屬性, 當使用框架時,需要給View的BindingContext指定對應的ViewModel:

  public class Install:MonoBehaviour
    {
        // Use this for initialization
        public SetupView setupView;
        public TestView testView;
        void Start()
        {
            //綁定上下文
            setupView.BindingContext=new SetupViewModel();
            testView.BindingContext=new TestViewModel();
        }
    }
在View中,就訂閱model數據改變的消息,並定義相應的響應函數:

 public class SetupView:UnityGuiView<SetupViewModel>
    {
        //......省略ui元素的定義
        
        protected override void OnInitialize()
        {
            base.OnInitialize();
            Binder.Add<string>("Name", OnNamePropertyValueChanged);
            Binder.Add<string>("Job",OnJobPropertyValueChanged);
            Binder.Add<int>("ATK",OnATKPropertyValueChanged);
            Binder.Add<float>("SuccessRate",OnSuccessRatePropertyValueChanged);
            Binder.Add<State>("State",OnStatePropertyValueChanged);
        }


        private void OnSuccessRatePropertyValueChanged(float oldValue, float newValue)
        {
            successRateMessageText.text = newValue.ToString("F2");
        }

        private void OnATKPropertyValueChanged(int oldValue, int newValue)
        {
            atkMessageText.text = newValue.ToString();
        }

        private void OnJobPropertyValueChanged(string oldValue, string newValue)
        {
            jobMessageText.text = newValue.ToString();
        }

        private void OnNamePropertyValueChanged(string oldValue, string newValue)
        {
            nameMessageText.text = newValue.ToString();
        }
        private void OnStatePropertyValueChanged(State oldValue, State newValue)
        {
           //dosomething
        }

最后看一下其中一個model的定義:

 public class Combatant
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Job { get; set; }
        public float SuccessRate { get; set; }
        public State State { get; set; }
    }
    public enum State
    {
        JoinIn,
        Wait
    }

 

4、總結

本文只大概寫了一下uMVVM框架的一些設計和使用方法,不全面,如果感興趣,可以自行閱讀源碼,github地址為 https://github.com/MEyes/uMVVM
 
如有錯誤,歡迎指正!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM