UE_Angelscript 实践篇——解耦 UI 蓝图的表现与逻辑#

UI 设计的时候,有各种各样的 UI 部件,它们的显示是最好在 UE 编辑器中操作的,毕竟所见即所得。它们的逻辑部分,一般情况是写在 UI 的蓝图中,但是因为 UI 部件十分多,维护起来就十分的麻烦。

自从用了 AS 的来写 UI 的逻辑,分散在各处的 UI 逻辑都被统一写到代码文件中了,管理起来十分方便,而且实现了显示与逻辑的解耦,UI 编辑器只负责显示,而脚本代码负责逻辑处理。

这是官方文档里也比较少介绍的内容。

UI 蓝图表现与逻辑分离的微型架构#

一句话:每一个 UE 编辑器里的小部件,都继承于某一个 AS 的类。

一般情况下,是一对一的关系,UI 部件和 AS 的类虽然是子类父类的关系,但是因为有了绑定,可以理解为是一种伴生的关系。

UI 部件之间继承的关系,最好都转移到 AS 的类之间,也即,尽量不要出现 UI 蓝图之间的继承关系,为什么?因为一旦蓝图之间继承了,一对一的关系被打破,事情变得麻烦,修改起来不那么直观了,这种情况多了之后,也许复杂度就大大提升。

以下,都以 Example_Widget_UMG.as 文件为简单的例子加以拓展描述。

这个微型架构的最开始,肯定是从 cpp 那里继承下来一个 UI 相关的类。

class UExampleWidget : UUserWidget

UI 蓝图 与 AS 类成员的对应关系#

每一个勾选为变量的 UI 蓝图部件,都会自动生成一个蓝图中的变量,而这个变量,可以在 AS 里进行绑定。

这个代码就是将 UI 蓝图名为 MainText 的 UTextBlock 绑定到 AS 里作为变量使用。 一旦绑定,蓝图的变量栏里就不会再出现这个变量。当然,蓝图还是可以使用这个变量的(如果蓝图里还想写逻辑)。

class UExampleWidget : UUserWidget
{
	// 将名为 MainText 的蓝图变量绑定到此 AS 变量
    UPROPERTY(BindWidget)
    UTextBlock MainText;
}

拓展:UI 蓝图经常有各类动画,动画也是可以绑定的,代码参数如下。

    UPROPERTY(BindWidgetAnim)
    UWidgetAnimation OnSpawned;

经过上面的操作,可以将需要的变量都绑定好,之后就是写逻辑了。

预构造和构造函数#

预构造函数和构造函数是经常要用的,它们的使用方式,与 UI 蓝图区别不大。

	UFUNCTION(BlueprintOverride)
	void PreConstruct(bool IsDesignTime)
	{
		AttributeNumber.Font.Size = 12;
	}

   UFUNCTION(BlueprintOverride)
    void Construct()
    {
    }

UI 事件的绑定#

如果是当前 UI 的类就有的事件,那么直接覆写对应的函数就可以了,比如 Button 就有 OnClicked、OnHovered 和 OnUnhovered 等。

如果想绑定的 UI 部件的事件,那么就需要用绑定委托的写法了。

这是 CommonUI 里的 Button 类的例子:

// 当前类就是需要绑定事件的主体,覆写函数即可
	UFUNCTION(BlueprintOverride)
	void OnClicked()
	{
	}

// 需要绑定事件的主体是类的成员,就绑定这个成员的委托
YourBoundButton.OnButtonBaseClicked.AddUFunction(this,n"OnButtonBaseClicked")

UI 蓝图的检查(可选)#

OnValidateCompiledWidgetTree 这个函数是 cpp 里用于检查 UI 蓝图的,如果检查不通过,可以在蓝图里抛出编译错误。

因为 UI 蓝图部件众多,它们的参数有时候需要特殊的配置,比如同样的部件,复制了几份,它们的不同除了名称外,还必须设置某个参数不同,那么就可以在这里进行检查了。

不过 UI 蓝图的错误抛出代码没有提供蓝图版本,AS 里也无法直接调用。这时候就需要做一些手工的包装与绑定了。最终实现的效果示例如下:

#if EDITOR
	UFUNCTION(BlueprintOverride)
	void OnValidateCompiledWidgetTree(const UWidgetTree BlueprintWidgetTree) const
	{
		if (OptionsClass.IsNull())
		{
			ShowCompileLog_Error("OptionsClass is null! Check and Set it in the Editor!");
		}
		if (UserFacingExperience == nullptr)
		{
			ShowCompileLog_Error("UserFacingExperienceDefinition is null! Check and Set it in the Editor!");
		}
		if (QuitGameClass.IsNull())
		{
			ShowCompileLog_Error("QuitGameClass is null! Check and Set it in the Editor!");
		}
	}
#endif

ShowCompileLog_Error 是自行在 cpp 里增加的一个函数,用于抛出错误。

这种包装与绑定略复杂,需要继承下来 UI 蓝图的常用类,然后再添加功能,这里略过。

UI 蓝图与其他类的解耦交互(可选)#

UI 蓝图与其他类交互时,通常需要编写大量引用代码,其中委托可以用来做一定程度的解耦,但是委托毕竟还是至少需要单向引用的,有没有办法让互不知道的两个类相互传递信息呢?有的,就是全局广播系统 UGameplayMessageSubsystem 。

这个 SubSystem 有 AS 的绑定,官方文档里提供了 GameplayMessageRouter with Angelscript 的绑定。其用法也比较简单,在 Readme 文件里可以看到,就不赘述。

通过这个系统,可以轻松地将 UI 蓝图与其他内容进行解耦。这个系统的使用记得注册为监听者之后,之后不需要的时候别忘记了注销。

总结#

让表现归于表现,让逻辑归于逻辑,就是常说的前后端分离,AS 对 UI 蓝图的伴生绑定,让这得以轻松实现。

另外这也顺带解决了一个问题——UI 蓝图之间的 Cast 会带来逐渐膨胀的资产引用问题,而代码之间的 Cast 就没有关系。

解耦 UI 蓝图的表现与逻辑,好处多多,大家都有光明的未来!


×

联系

问题反馈

问题与反馈请提交至 GitHub Issues。

合作

合作事宜请发送邮件至 contact@cuviss.com。

×

关于

服务条款

各插件的许可证见社区贡献页。

网站内容可在注明来源后引用。

软件和文档按“现状”提供,不作任何保证。

Unreal Engine 等第三方项目及名称相关商标归各自所有者所有。soloAS 与 Epic Games、Hazelight 均无关联。

致谢和案例展示请求均不具约束力,详见首页说明。

更新于 2026-10-24

隐私政策

本网站不使用分析工具、Cookie 或跟踪,也没有数据表单或第三方脚本。

网站托管于 GitHub Pages。GitHub 可能按其隐私声明处理标准访问日志。

通过邮件发送的内容会提供给我们;通过 GitHub Issues 发送的内容会提供给 GitHub。

更新于 2026-10-24

目录

页面列表

本页目录