mvvm test

334 阅读2分钟

mvc示意图

image.png

  • 用户通过试图进行输入,通知Control进行处理
  • Control要求Model改变状态
  • Control也可以要求View改变显示
  • View一般向Model注册事件,Model改变,会通知view做出相应改变
  • View也会持有model的引用,也可以直接访问model的某些数据
public class Model
{
    private bool a;
    public bool A
    {
        get => a;
        set
        {
            a = value;
            //4.model通知view
            temp?.Invoke(a);
        }
    }
    public event Action<bool> temp;
    public void Add(Action<bool> a)
    {
        temp += a;
    }
}

public class Control
{
    //省略初始化
    private Model model;
    private View view;
    public Control(Model model)
    {
        this.model = model;
        this.view = new View(model,this);
    }
    public void SetA(bool a)
    {
        //2.改变model状态
        model.A = a;
        //3.改变view显示
        view.SetActive();
    }
}

public class View
{
    private Model model;
    private Control control;
    public Text text;
    public Toggle toggle;
    public View(Model model,Control control)
    {
        this.model = model;
        this.control = control;
        model.Add(function);
        //1.用户输入
        toggle.onValueChanged.AddListener(control.SetA);
    }
    public void function(bool a) { 
        toggle.isOn = a;
    }
    public void SetActive()
    {
        //5.获取数据
        bool active = model.A;
        text.gameObject.SetActive(active);
    }

}

MVVM示意图

image.png

  • view :ui界面,显示数据并与用户交互
  • model:实体数据,包括本地和远程
  • viewmodel:负责完成View于Model间的交互,负责业务逻辑

双向绑定和单向绑定

  • 单项绑定:view变化不通知viewmodel,viewmodel变化会反映在view上,例如text
  • 双向绑定:view和viewmodel变化后,都互相通知对方,例如toggle

单项绑定原理

image.png

双向绑定原理

image.png

无限滑动列表原理

image.png

UI整体结构

image.png

案例

-- view
local function OnCreate(self)
        self:Bind("my_tog","toggle")
	self:Bind("my_btn.visible","toggle")
end
-- viewmodel
function UILoginViewModel:OnCreate()
    self.toggle = BindableProperty.New(true)
end

绑定背后

  • 设置manifest image.png

  • 更具manifest上的名称获取unity对应component,在获取相应的lua封装component

    C2LuaType = {
        ["UnityEngine.UI.Button"] = UIButton,
        ["UnityEngine.UI.InputField"] = UIInput,
        ["UnityEngine.UI.Slider"] = UISlider,
        ["UnityEngine.UI.Text"] = UIText,
        ["UnityEngine.UI.Image"] = UIImage,
        ["UnityEngine.UI.Toggle"] = UIToggle,
        ["UnityEngine.UI.Dropdown"] = UIDropdown,
    },
  • component 进行绑定
local UIButton = BaseClass("UIButton", UIBaseComponent)
local base = UIBaseComponent
local error = error
local PropertiesHelper = require "Framework.UI.Wrapper.PropertiesHelper"
-- 创建
function UIButton:OnCreate(item, binder)
	base.OnCreate(self)
	self._origin = item
	-- Unity侧原生组件
	self.unity_uibutton = item
	self.binder = binder
	assert(not IsNull(self.unity_uibutton), "Err : unity_uibutton nil!")
end

--- property bind 
local _interactable = "interactable"
function UIButton:interactable(property_name)
	if self:IsBinded(_interactable) then
		error(("UIButton %s has bind"):format(_interactable))
		return
	end
	self.binder:Add(property_name, function (oldValue, newValue)
		if oldValue ~= newValue then
			self.unity_uibutton.interactable = newValue
		end
	end)
	self:RecordProperty(_interactable)
end

local _onClick = "onClick"
function UIButton:onClick(property_name)
	if self:IsBinded(_onClick) then
		error(("UIButton %s has bind"):format(_onClick))
		return
	end
	self.binder:RegisterEvent(function(viewModel, property)
		self.unity_uibutton.onClick:AddListener(property)
	end,nil, property_name)
	self:RecordProperty(_onClick)
end

-- 资源释放
function UIButton:OnDestroy()
	self.unity_uibutton.onClick:RemoveAllListeners()
	self.unity_uibutton = nil
	self.__onclick = nil
	base.OnDestroy(self)
end
return PropertiesHelper:Extends(UIButton)

UI层级

image.png

  • 二者都是值越小越先渲染

lua 面向对象

-- 简介

local UIItemsProxy = {
    __index = function(t,k)
        error(("items.%s not exist."):format(k))
    end,
    __newindex = function(t,k,v)
        error(("UIItemsProxy is readonly. attempt to modifying '%s' was ignored."):format(k))
    end
}
    
function UIItemsProxy:New(manifest)
    local o = {}
    setmetatable(o, self)
    return o
end

return UIItemsProxy
local class = require("framework.lib.middleclass") 
local super = require("framework.lib.super") 
local ActorRunner = class("ActorRunner",super)

function ActorRunner:initialize(caster, actor_id)
    
end

return ActorRunner

--使用
local a = ActorRunner:new(...)