Unity MVVM框架Loxodon:高性能数据绑定与UI开发实战指南
1. 项目概述为什么Unity开发者需要关注MVVM与Loxodon Framework如果你在Unity项目里做过稍微复杂一点的UI尤其是那种带点状态管理、数据驱动更新的界面大概率经历过这样的场景一个按钮点击后需要更新文本、刷新列表、改变图片同时还要处理网络请求回来的数据。代码写着写着Find和GetComponent满天飞Update方法里塞满了各种状态判断MonoBehaviour脚本越来越臃肿逻辑和视图紧紧耦合在一起改一处而动全身调试起来像在走迷宫。这就是传统Unity UI开发模式我们常说的“MVC”变种或者干脆叫“面条式代码”的典型痛点。逻辑和表现层纠缠不清不仅代码难以维护和测试团队协作也容易互相“踩脚”。而MVVMModel-View-ViewModel架构正是为了解决这类问题而生的设计模式。它通过引入一个“ViewModel”作为中间层将数据Model和界面View彻底解耦。View只负责展示和用户交互ViewModel持有数据并暴露可绑定的属性Model则专注业务逻辑和数据。三者通过数据绑定Data Binding机制自动同步你只需要在ViewModel里改个属性值View上对应的UI元素就会自动更新无需手动调用一堆SetText、SetActive。那么Loxodon Framework就是专门为Unity3D量身打造的一款轻量级、高性能的MVVM框架。它不是那种大而全的“重型武器”而是瞄准了Unity开发中的UI和数据绑定这个核心痛点提供了一套优雅的解决方案。我最初接触它是因为在一个需要频繁更新复杂列表和状态的中重度手游项目里传统的UI管理方式已经成了性能瓶颈和维护噩梦。尝试了Loxodon之后最直观的感受就是代码变干净了逻辑清晰了因为数据绑定带来的UI更新效率也肉眼可见地提升了特别是它通过动态委托和静态代码织入等技术几乎做到了绑定更新零GC垃圾回收这对移动端性能至关重要。所以无论你是正在被UI代码折磨的独立开发者还是团队里负责前端模块的程序如果你想提升Unity项目的代码质量、可维护性和性能尤其是UI部分花10分钟了解一下Loxodon Framework绝对是一笔划算的时间投资。它上手不难但带来的开发体验提升是巨大的。2. Loxodon Framework核心设计思路与优势解析2.1 不是简单的“轮子”而是针对Unity的深度优化市面上MVVM框架不少比如Prism、MVVM Light等但它们大多是为WPF、Xamarin等桌面或移动应用框架设计的直接搬到Unity里会有些“水土不服”。Unity的GameObject/Component体系、生命周期Awake,Start,Update、以及基于帧循环的渲染更新都决定了其UI框架的特殊性。Loxodon Framework的设计哲学很明确原生拥抱Unity极致优化性能。它不是简单地把一个通用MVVM框架移植过来而是从底层就为Unity做了大量适配和优化。首先它完美融入了Unity的组件系统。你的View就是一个继承自UIView或WindowView的MonoBehaviour可以像普通脚本一样挂在GameObject上通过Inspector面板拖拽绑定UI元素。ViewModel则是纯粹的C#类不依赖任何Unity引擎对象方便单元测试。这种设计让熟悉Unity的开发者几乎无学习成本就能开始使用。其次也是它最核心的竞争力高性能数据绑定。很多绑定框架底层依赖反射Reflection来获取和设置属性值这在需要每帧更新的UI场景下是性能灾难。Loxodon采用了两种关键技术来规避动态委托Dynamic Delegate在运行时为每个需要绑定的属性生成高效的委托方法避免了反射调用。静态代码织入Static Code Weaving via Fody这是一个“黑科技”。在编译阶段通过Fody插件如Loxodon.Framework.Fody.PropertyChanged直接修改IL代码在属性的set访问器中自动插入触发属性变更通知的代码。这样性能就和直接调用属性Setter一样快并且完全消除了运行时反射开销。此外框架在数据绑定过程中极力避免值类型的装箱Boxing和拆箱Unboxing操作。比如绑定一个int到Text组件框架内部会使用泛型等机制确保int直接以值类型传递和格式化不会产生额外的内存分配GC Alloc。对于字符串拼接、数字转字符串这种UI更新中的高频操作它提供了TextFormatting插件扩展了StringBuilder同样以实现零GC为目标。2.2 清晰的架构与丰富的生态Loxodon Framework的架构非常清晰核心就是Loxodon.Framework这个主模块提供了ViewModel基类、绑定引擎、命令系统、消息系统、本地化等基础功能。围绕这个核心有一系列官方插件来扩展能力形成了一个小而美的生态Loxodon.Framework.XLua/Loxodon.Framework.ILRuntime支持使用Lua或ILRuntime进行热更新开发ViewModel和绑定逻辑可以用C#或脚本语言编写这对需要热更的游戏项目是刚需。Loxodon.Framework.Bundle一个功能完善的AssetBundle管理器支持依赖分析、冗余资源检测、模拟模式等解决了Unity资源管理的另一大痛点。Loxodon.Framework.OSA为Optimized ScrollView Adapter这个高性能滚动列表插件提供了数据绑定支持让你能用MVVM的模式来驱动复杂的滚动列表性能与便利兼得。Loxodon.Framework.UIToolkit随着Unity新版UI系统UIToolkit的普及这个插件提供了对UIToolkit的绑定支持允许你混合使用UGUI和UIToolkit。Loxodon.Framework.Data提供了从Excel配置表导出为Json、Lua或LiteDB数据库的工具链方便游戏配置数据管理。Loxodon.Framework.Obfuscation内存数值混淆工具用于防止简单的内存修改器作弊对单机或弱联网游戏有一定保护作用。这种模块化设计的好处是你可以按需取用。如果只是想做UI和数据绑定引入核心库就够了如果项目有滚动列表、热更、配置表等特定需求再引入对应的插件不会造成不必要的臃肿。注意虽然插件丰富但建议新手先从核心的MVVM和数据绑定功能开始不要一开始就试图把所有插件都用上。理解核心思想比堆砌功能更重要。3. 10分钟快速上手创建你的第一个数据绑定UI理论说了这么多我们来点实际的。目标是创建一个简单的进度条界面包含一个滑动条Slider、一个显示百分比的文本Text和一个提示文本Text。我们将用MVVM模式实现通过代码控制ViewModel的数据UI自动更新。3.1 环境准备与框架导入首先你需要一个Unity项目2018.4或更高版本推荐使用.NET 4.x Equivalent或.NET Standard 2.0的API兼容级别。Loxodon Framework的导入非常方便主要有两种方式使用Unity Package Manager (UPM) 从Git URL安装推荐 这是最干净的方式。打开Unity进入Window - Package Manager。点击左上角的“”号选择“Add package from git URL...”。输入核心框架的Git地址https://github.com/vovgou/loxodon-framework.git。等待Unity下载和编译即可。这种方式便于版本管理依赖清晰。从Asset Store或下载Release包导入 你也可以从Unity Asset Store搜索“Loxodon Framework”购买或者从GitHub的Release页面下载.unitypackage文件直接导入项目。这种方式适合网络受限的环境但需要注意手动管理依赖和更新。导入成功后你会在项目的Packages目录下看到Loxodon Framework或者如果使用.unitypackage会在Assets目录下看到Loxodon文件夹。3.2 创建ViewModel数据的持有者ViewModel是一个纯C#类它继承自ViewModelBase。它的职责是封装与视图相关的状态和数据并提供这些数据的可绑定属性。在项目中创建一个C#脚本命名为ProgressBarViewModel.cs。代码如下using Loxodon.Framework.Observables; // 引入命名空间 public class ProgressBarViewModel : ViewModelBase { // 私有字段 private string _tip; private float _progressValue; // 公开属性用于数据绑定 public string Tip { get { return _tip; } set { this.Setstring(ref _tip, value, nameof(Tip)); } // 关键Set方法会检查值变化并通知视图 } public float ProgressValue { get { return _progressValue; } set { this.Setfloat(ref _progressValue, value, nameof(ProgressValue)); } } // 可以在这里定义命令ICommand用于响应按钮点击等操作 // public ICommand StartDownloadCommand { get; private set; } public ProgressBarViewModel() { // 初始化属性和命令 Tip 准备就绪; ProgressValue 0f; // StartDownloadCommand new AsyncCommand(OnStartDownload); } // private async Task OnStartDownload() // { // // 模拟下载逻辑 // Tip 下载中...; // for (int i 0; i 100; i) // { // await Task.Delay(50); // 模拟耗时 // ProgressValue i / 100f; // Tip $下载中...{i}%; // } // Tip 下载完成; // } }代码解读ViewModelBase提供了数据绑定所需的基础设施特别是SetT(ref T field, T value, string propertyName)方法。这个方法在设置字段新值前会先比较旧值如果值确实改变了它会自动触发PropertyChanged事件通知所有绑定了该属性的UI进行更新。nameof(Tip)是C# 6.0的语法用于安全地获取属性名字符串避免硬编码。属性是数据绑定的桥梁。UI组件将绑定到这些属性上。注释部分展示了如何结合AsyncCommand来处理异步操作如下载这是MVVM中处理交互逻辑的推荐方式可以让ViewModel完全独立于视图的细节。3.3 创建View界面的展示者View是继承自UIView的MonoBehaviour它附着在GameObject上负责查找UI组件并建立它们与ViewModel属性的绑定关系。创建一个C#脚本命名为ProgressBarView.cs并将其挂载到你的UI Canvas下的一个空GameObject或进度条面板的根节点上。using Loxodon.Framework.Binding; // 引入绑定相关命名空间 using Loxodon.Framework.Binding.Builder; // 引入绑定构建器 using Loxodon.Framework.Contexts; // 引入上下文用于获取ViewModel using UnityEngine; using UnityEngine.UI; // 如果是UGUI public class ProgressBarView : UIView { // 在Inspector中拖拽赋值 public Text tipText; public Text progressText; public Slider progressSlider; // 声明对ViewModel的引用 private ProgressBarViewModel viewModel; protected override void Start() { base.Start(); // 从上下文或直接创建获取ViewModel实例 // 这里为了简单直接new一个。实际项目中可能通过IoC容器获取。 viewModel new ProgressBarViewModel(); this.SetDataContext(viewModel); // 设置View的数据上下文 // 创建绑定关系 CreateBinding(); } private void CreateBinding() { // 使用BindingSet来创建一组绑定 var bindingSet this.CreateBindingSetProgressBarView, ProgressBarViewModel(); // 绑定Tip属性到tipText的text属性 // For(v v.text) 指定View上的目标属性Text组件的text // To(vm vm.Tip) 指定ViewModel上的源属性 // OneWay() 表示单向绑定从ViewModel到View bindingSet.Bind(tipText).For(v v.text).To(vm vm.Tip).OneWay(); // 绑定ProgressValue属性到progressSlider的value属性 // TwoWay() 表示双向绑定Slider的值改变也会更新ViewModel bindingSet.Bind(progressSlider).For(v v.value).To(vm vm.ProgressValue).TwoWay(); // 绑定ProgressValue属性到progressText的text但需要格式化 // ToExpression 允许使用表达式进行复杂的转换或格式化 bindingSet.Bind(progressText).For(v v.text) .ToExpression(vm string.Format({0:P0}, vm.ProgressValue)) // 格式化为百分比 .OneWay(); // 构建绑定 bindingSet.Build(); } // 示例提供一个按钮点击方法来触发ViewModel中的命令如果用了AsyncCommand // public void OnStartButtonClicked() // { // viewModel.StartDownloadCommand.Execute(null); // } }操作步骤在Unity编辑器中创建一个简单的UI一个Slider两个Text一个作为提示一个显示百分比。将ProgressBarView脚本挂载到一个GameObject上比如一个名为ProgressBarPanel的Panel。将这个GameObject的tipText、progressText、progressSlider字段分别拖拽赋值给场景中对应的UI组件。运行游戏。你应该能看到Slider的值为0文本显示“0%”和“准备就绪”。3.4 测试数据绑定为了看到效果我们可以写一个简单的脚本来驱动ViewModel数据变化。创建一个测试脚本TestDriver.csusing UnityEngine; public class TestDriver : MonoBehaviour { public ProgressBarView progressBarView; // 拖拽赋值 private ProgressBarViewModel vm; void Start() { if (progressBarView ! null) { // 获取View中设置的ViewModel vm progressBarView.GetDataContext() as ProgressBarViewModel; if (vm ! null) { StartCoroutine(SimulateProgress()); } } } System.Collections.IEnumerator SimulateProgress() { vm.Tip 模拟加载中...; for (int i 0; i 100; i) { vm.ProgressValue i / 100f; yield return new WaitForSeconds(0.05f); // 每0.05秒更新一次 } vm.Tip 加载完成; } }将这个脚本也挂载到场景中某个对象上并将ProgressBarView组件拖拽赋值给它。运行游戏你会看到进度条自动滑动文本实时更新而你没有在View脚本里写任何更新UI的代码如slider.value ...或text.text ...。所有UI变化都源于ViewModel属性的改变这就是数据绑定的魔力。实操心得在Inspector中拖拽绑定引用时务必确保类型匹配。比如tipText字段是Text类型就不能拖一个GameObject进去。良好的命名习惯如View后缀、ViewModel后缀和文件夹组织如Scripts/View/,Scripts/ViewModel/在项目规模变大后至关重要。4. 核心机制深度解析绑定、命令与上下文4.1 数据绑定DataBinding的多种姿势上面的例子展示了最基本的属性绑定。Loxodon Framework的绑定系统非常强大支持多种绑定模式单向绑定 (OneWay)数据从ViewModel流向View这是最常用的模式用于显示数据。双向绑定 (TwoWay)数据在ViewModel和View之间双向同步。典型应用就是InputField或Slider用户修改UIViewModel的值也随之改变。一次性绑定 (OneTime)仅在绑定建立时从ViewModel获取一次数据之后不再同步。适用于静态数据。反向绑定 (OneWayToSource)数据从View流向ViewModel相对少见。除了绑定到简单属性还支持更复杂的场景集合绑定将ObservableListT或ObservableDictionaryTKey, TValue绑定到ListView或GridView需要OSA插件。当集合增删改时UI列表会自动更新无需手动管理Item的创建和销毁。// ViewModel中 public ObservableListItemViewModel ItemList { get; } new ObservableListItemViewModel(); // View中绑定 bindingSet.Bind(listView).For(v v.Items).To(vm vm.ItemList).OneWay();事件绑定将UI事件如Button.onClick直接绑定到ViewModel的命令ICommand或方法。bindingSet.Bind(button).For(v v.onClick).To(vm vm.SubmitCommand).OneWay();表达式绑定使用ToExpression进行简单的数据转换或格式化就像我们在进度百分比文本中做的那样。值转换器 (IValueConverter)当源数据和目标数据格式不一致时使用。例如ViewModel中有一个bool类型的IsActive你想绑定到GameObject的activeSelf属性需要bool这可以直接绑定。但如果你想绑定到一个Image的colorColor类型当IsActive为true时显示绿色false时显示灰色就需要一个BoolToColorConverter。// 首先定义一个转换器 public class BoolToColorConverter : IValueConverter { public Color trueColor Color.green; public Color falseColor Color.gray; public object Convert(object value) { return (bool)value ? trueColor : falseColor; } public object ConvertBack(object value) { return null; } // 单向转换不需要 } // 在View中注册并使用 bindingSet.Bind(image).For(v v.color).To(vm vm.IsActive).WithConversion(boolToColor).OneWay();4.2 命令Command与异步命令AsyncCommand在MVVM中View如Button的交互动作不应该直接调用业务逻辑而应该触发ViewModel中的命令。Loxodon提供了ICommand接口的实现。普通命令 (Command)用于执行同步操作。public ICommand ClickCommand { get; private set; } this.ClickCommand new Command(OnClick); private void OnClick() { /* 同步处理 */ }异步命令 (AsyncCommand)这是Loxodon的一大亮点专门用于处理async/await异步操作。它内部处理了异步方法的执行、异常捕获并自动管理命令的CanExecute状态例如在任务执行期间禁用按钮。public AsyncCommand DownloadCommand { get; private set; } this.DownloadCommand new AsyncCommand(OnDownloadAsync); private async Task OnDownloadAsync() { // 异步操作如网络请求 Tip 开始下载...; await SomeDownloadFunction(); Tip 下载完成; }使用AsyncCommand后你无需手动在异步操作前后启用/禁用按钮框架会自动处理极大地简化了异步UI交互的代码。4.3 上下文Context与依赖注入IoC在简单的demo中我们直接在View里new了一个ViewModel。但在实际项目中ViewModel可能依赖其他服务如网络模块、数据存储层。直接new会导致耦合度高难以测试。Loxodon Framework包含一个轻量级的上下文Context和依赖注入IoC容器。通常你会在游戏启动时创建一个ApplicationContext并在这里注册各种服务单例和ViewModel的映射关系。// 在游戏入口处如一个GameLauncher脚本 public class GameLauncher : MonoBehaviour { void Awake() { // 创建应用上下文 ApplicationContext context Context.GetApplicationContext(); // 获取IoC容器 IServiceContainer container context.GetContainer(); // 注册服务单例例如一个模拟的数据服务 container.RegisterIDataService(new DataService()); // 注册ViewModel可以指定如何创建实例 container.RegisterProgressBarViewModel(new ProgressBarViewModel()); // 或者使用工厂方法 // container.RegisterProgressBarViewModel(() new ProgressBarViewModel(container.ResolveIDataService())); } } // 在View中通过上下文获取ViewModel public class ProgressBarView : UIView { protected override void Start() { base.Start(); // 不再直接new而是从上下文解析 var viewModel Context.GetApplicationContext().GetServiceProgressBarViewModel(); this.SetDataContext(viewModel); CreateBinding(); } }使用IoC容器后ViewModel的依赖可以被自动注入提高了代码的可测试性和可维护性。对于中小型项目你可能觉得略显复杂但对于大型项目或团队协作这是非常值得引入的实践。5. 实战进阶与性能优化要点5.1 列表视图ListView的高性能绑定UI中最耗性能的部分之一就是滚动列表。Loxodon Framework通过Loxodon.Framework.OSA插件与Optimized ScrollView Adapter这个顶级性能的滚动列表插件深度集成实现了MVVM模式下的高性能列表。核心思路你不是直接实例化成百上千个Item的GameObject而是创建一个Item的视图模板Prefab和一个对应的ItemViewModel。将一列ObservableListItemViewModel绑定到ListView或GridView上。OSA插件会基于视图端口只创建和复用少量Item实例当数据源变化时自动更新对应的Item视图。基本步骤安装Optimized ScrollView Adapter和Loxodon.Framework.OSA插件。创建Item的Prefab并挂载一个继承自UIView的脚本如ItemView在其中绑定ItemViewModel的属性到Prefab上的UI元素。创建ItemViewModel类。在主ViewModel中创建ObservableListItemViewModel。在主View中获取ListView组件并通过绑定将主ViewModel的List绑定到ListView的Items属性。// 主View中的绑定 [SerializeField] private ListView listView; // 在Inspector中拖拽OSA的ListView组件 private MainViewModel mainVM; bindingSet.Bind(listView).For(v v.Items).To(vm vm.ItemList).OneWay();这样当你对ItemList进行Add、Remove、Clear或修改其中某个ItemViewModel的属性时列表UI会自动、高效地更新。这比手动管理Instantiate和Destroy以及在Update里刷新数据要优雅和高效得多。5.2 内存与GC优化实战Loxodon Framework在设计之初就将性能作为重中之重。但要发挥其最大效能开发者也需要遵循一些最佳实践优先使用TextFormatting或TextMeshPro插件UI中频繁更新的文本是GC的主要来源。框架的TextFormatting插件提供了TemplateText和FormattableText组件TextMeshPro插件提供了对应的TemplateTextMeshProUGUI和FormattableTextMeshProUGUI。它们内部使用优化的字符串构建器能极大减少甚至消除文本更新时的GC分配。在性能要求高的项目里应该用这些组件替代标准的UnityEngine.UI.Text。// 使用FormattableText bindingSet.Bind(formattableText).For(v v.text).To(vm vm.Score).OneWay(); // 在ViewModel中Score可以是int, float等更新时几乎无GC。避免在频繁调用的代码路径中创建新的ViewModel或绑定CreateBindingSet()和Build()操作有一定开销应在Awake或Start中一次性完成。对于动态创建的UI如弹窗应考虑使用对象池来复用View和ViewModel。谨慎使用表达式绑定和值转换器复杂的表达式或转换器在每次属性更新时都会执行。确保它们逻辑简单高效。对于复杂的转换考虑在ViewModel中预先计算好一个用于绑定的属性。利用ObservablePropertyT包装值类型对于简单的值类型属性框架的SetT方法已经做了优化。但对于需要在属性变更时执行额外逻辑的情况可以使用ObservablePropertyT它同样实现了INotifyPropertyChanged且性能优化过。public ObservablePropertyfloat Progress { get; } new ObservablePropertyfloat(0f); // 绑定方式相同 bindingSet.Bind(slider).For(v v.value).To(() Progress.Value).TwoWay();5.3 常见问题排查与调试技巧即使框架设计得再好实际开发中也会遇到问题。这里记录几个我踩过的坑和解决方法绑定不生效UI不更新检查点1属性通知是否触发。确保在ViewModel属性的set中使用了this.SetT(...)方法。如果直接赋值给字段View是无法感知的。检查点2绑定路径是否正确。检查To(vm vm.YourProperty)中的属性名拼写是否正确大小写是否匹配。检查点3绑定模式是否匹配。如果你期望View修改能更新ViewModel需要使用TwoWay()绑定。OneWay()是单向的。检查点4DataContext是否正确设置。确保在View的Start或Awake中调用了this.SetDataContext(viewModel)并且传入的viewModel不为null。调试工具Loxodon Framework有简单的日志输出。在Player Settings中启用脚本调试并在代码开始时设置Log.level LogLevel.DEBUG;可以在Console中看到详细的绑定创建和执行日志。使用AsyncCommand时按钮点击后无反应或状态不对检查点异步方法是否抛出未捕获的异常。AsyncCommand内部会捕获异常并记录日志但异常会导致命令执行中断。确保你的async Task方法内部有良好的异常处理try-catch。观察按钮的交互状态AsyncCommand在执行期间会自动将CanExecute设为false这通常会禁用关联的按钮。这是正常行为。如果你的按钮没有禁用检查按钮的interactable属性是否正确地绑定到了命令的CanExecute通常框架的ButtonBinding会处理这个。在IL2CPP编译时出现错误Loxodon Framework 2.0 版本已经支持IL2CPP。但如果使用了代码织入Fody插件需要确保在IL2CPP下链接器不会“剪掉”被织入的代码。通常需要在Assets目录下创建一个link.xml文件来保留必要的程序集和类型。!-- link.xml -- linker assembly fullnameYourAssemblyName preserveall/ !-- 保留Loxodon的核心程序集 -- assembly fullnameLoxodon.Framework preserveall/ /linker与第三方UI插件如DoTween, LeanTween的兼容性通常没有直接冲突。但要注意如果你在View的脚本里用这些插件做动画并且动画的目标值是绑定到ViewModel的属性可能会产生循环更新。建议的做法是动画驱动ViewModel而非直接驱动View。例如使用DoTween的DOValue方法来改变ViewModel中的一个float属性然后通过数据绑定自动更新UI。这样逻辑更清晰。6. 项目集成建议与学习路径6.1 在新老项目中如何引入全新项目强烈建议从一开始就采用。可以快速搭建起清晰的数据驱动UI架构。先从核心的MVVM和数据绑定开始随着功能复杂再逐步引入命令、IoC、列表绑定等高级特性。已有项目不建议一次性全盘重构。可以采用“渐进式”策略局部试点选择一个功能相对独立、UI逻辑复杂的模块如设置界面、角色背包进行重写验证效果和熟悉框架。新功能优先所有新开发的UI功能强制使用Loxodon Framework来实现。逐步重构在维护旧功能时如果有较大的改动需求可以顺便将其重构为MVVM模式。6.2 推荐的学习资源与下一步官方文档与示例Git仓库中的docs文件夹和Tutorials示例场景是最好的学习材料。务必仔细阅读README和Installation文档。源码阅读框架的代码结构清晰注释良好。当你对某些机制如绑定如何建立、命令如何执行感到好奇时直接阅读源码是最高效的理解方式。社区框架作者在GitHub上积极维护Issues里有很多典型问题的讨论。提到的QQ群622321589, 15034148也是国内开发者交流的好地方。下一步探索深入本地化Localization框架内置了强大的本地化支持可以轻松实现多语言UI。研究消息系统Messenger用于ViewModel之间或跨模块的松耦合通信。集成状态管理对于超大型项目可以考虑在ViewModel之上引入更专门的状态管理库如UniRx但Loxodon的基础绑定已经能覆盖大部分场景。从我个人的使用经验来看Loxodon Framework最打动我的地方在于它在“优雅”和“性能”之间取得了极佳的平衡。它没有为了设计模式而引入过度复杂的抽象所有功能都紧紧围绕着提升Unity UI开发体验这个实际目标。上手的第一周可能会觉得要多写一些ViewModel的“样板代码”但一旦习惯你会发现调试变得简单UI逻辑和业务逻辑分离得清清楚楚代码复用率大大提高特别是面对复杂动态UI时那种一切尽在掌控的感觉非常棒。如果你正在寻找一个能提升团队UI开发效率和项目质量的框架Loxodon绝对值得你投入这“10分钟”去尝试并深入使用下去。