news 2026/9/6 16:34:25

Bevy UI 圆角迁移指南:BorderRadius 字段变为 CornerRadius,ResolvedBorderRadius 变为 Vec2

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Bevy UI 圆角迁移指南:BorderRadius 字段变为 CornerRadius,ResolvedBorderRadius 变为 Vec2

Bevy UI 圆角迁移指南:BorderRadius 字段变为 CornerRadius,ResolvedBorderRadius 变为 Vec2

【免费下载链接】bevyA refreshingly simple>项目地址: https://gitcode.com/GitHub_Trending/be/bevy

本篇指南围绕 Bevy UI 的一次破坏性 API 变更展开:为支持椭圆(elliptical)圆角节点,BorderRadius的四个角字段由Val变为CornerRadiusResolvedBorderRadius的字段由标量f32变为Vec2。读完本文,你将掌握新旧 API 的逐项对照写法、CornerRadius的循环/椭圆语义与解析(resolve)规则,并能顺畅地完成现有 UI 代码的迁移。

背景:为什么字段要变成二维

官方迁移指南 border_radius.md(对应 PR 24779)给出的变更说明只有一句话:

In order to support elliptical nodes, the fields ofBorderRadiusare nowCornerRadiuss and the fields ofResolvedBorderRadiusare nowVec2s.

即:为了支持椭圆圆角节点,BorderRadius的字段改为CornerRadiusResolvedBorderRadius的字段改为Vec2。对应的功能发布说明见 Elliptical Border Radius。

在旧版 API 中,每个角的圆角半径只有一个Val,隐含"圆形"语义。新版允许 x(水平)与 y(垂直)半径不同,从而画出一个椭圆的角。所有改动都集中在bevy_ui的两个文件里:

  • crates/bevy_ui/src/geometry.rs:新增的CornerRadius类型;
  • crates/bevy_ui/src/ui_node.rs:BorderRadiusResolvedBorderRadius

迁移对照:BorderRadius 的新旧写法

变更前

BorderRadius { pub top_left: px(10.), pub top_right: percent(20.), pub bottom_right: zero(), pub bottom_left: vh(5.), }

变更后

BorderRadius { pub top_left: CornerRadius::circular(px(10.)), pub top_right: CornerRadius::circular(percent(20.)), pub bottom_right: CornerRadius::circular(zero()), pub bottom_left: CornerRadius::circular(vh(5.)), }

由于CornerRadius实现了From<Val>(见 geometry.rs),你也可以用into完成同样的转换:

BorderRadius { pub top_left: px(10.).into(), pub top_right: percent(20.).into(), pub bottom_right: zero().into(), pub bottom_left: vh(5.).into(), }

从源码结构看,From<Val>的实现是Self { x, y: auto() },即把原值放进xy设为Val::Auto——这正好命中下一节讲的"圆形"表示。因此绝大多数只写圆形圆角的旧代码可以靠.into()最小改动地迁移。

新类型 CornerRadius:结构与圆形/椭圆语义

CornerRadius的定义在 crates/bevy_ui/src/geometry.rs:

pub struct CornerRadius { /// Responsive horizontal radius. pub x: Val, /// Responsive vertical radius. pub y: Val, }

两个字段都是响应式的Val,可以取pxpercentvh/vwem/rem等任意响应式值。

圆形圆角的表示方式:Val::Auto

迁移指南明确说明:圆形圆角(circular corner radius)的表示方式是让CornerRadius::xCornerRadius::y其中一个为Val::Auto

对应的构造辅助函数是circular(geometry.rs):

/// Creates a circular corner radius, with `radius` resolved relative to the node's /// shortest side and clamped to half its length. pub const fn circular(radius: Val) -> Self { Self { x: radius, y: Val::Auto, } }

CornerRadius还提供了两组常量和两个常用构造器:

常量/方法定义语义
CornerRadius::MAX{ x: Px(f32::MAX), y: Val::Auto }完全圆角:半径为节点最短边的一半,节点呈胶囊形(宽高相等时为圆形)
CornerRadius::MAX_ELLIPTICAL{ x: Px(f32::MAX), y: Px(f32::MAX) }完全椭圆角:水平半径为宽的一半,垂直半径为高的一半,节点被画成椭圆
CornerRadius::ZERO{ x: ZERO, y: ZERO }直角
circular(radius){ x: radius, y: Auto }圆形角,半径相对节点最短边解析,并钳制到其一半
all(radius){ x: radius, y: radius }两轴同值。注意:由于各轴独立解析(percent 等值对宽高各自取值),解析结果不一定相等
new(x, y){ x, y }椭圆角,分别指定水平/垂直半径

一个容易踩的点是allcircular的区别。源码文档测试(geometry.rs)表明:对 100x50 的节点,all(px(30.))解析为Vec2::new(30., 25.)——x 轴钳制到宽度一半(50),y 轴钳制到高度一半(25);而circular(px(30.))会先对最短边(50)解析,再钳制到 25,得到Vec2::splat(25.),保证两轴严格相等、形状是圆弧而不是椭弧。

可传入的输入类型:From 实现一览

BorderRadius的所有构造函数参数类型是impl Into<CornerRadius>,因此凡是可以转换为CornerRadius的类型都能传入。源码中提供了如下转换(geometry.rs):

  • From<Val>px(10.).into(),等价于circular
  • From<(Val, Val)>(px(10.), px(20.)).into()
  • From<[Val; 2]>[px(10.), px(20.)].into()

此外BorderRadius本身实现了From<T: Into<CornerRadius>>(ui_node.rs),直接调用Self::all(value),所以BorderRadius::from(px(10.))等于四角全圆角。

一个值得注意的设计细节是PartialEq的实现(geometry.rs):{ x: v, y: Auto } == { x: Auto, y: v }判定为相等。因为Auto只是"另一轴未显式设置、按圆形半径解释"的标记,两种摆放方式语义相同。这意味着CornerRadius::circular(r){ x: r, y: auto() }{ x: auto(), y: r }在比较时一致,迁移后做assert_eq!时不必纠结Auto放在哪一轴。

resolve:解析成物理像素的规则

CornerRadius::resolve(geometry.rs)把响应式半径解析为物理像素Vec2,签名与Val::resolve一致:

pub fn resolve( self, scale_factor: f32, size: Vec2, // 节点尺寸 viewport_size: Vec2, em_size: EmSize, rem_size: RemSize, ) -> Vec2

分支逻辑是:

  1. 两轴都是Auto→ 返回Vec2::ZERO
  2. 一轴为Auto(即圆形模式)→ 用非 Auto 轴的值对节点最短边size.min_element()解析,钳制到[0, 0.5 * min(size)],然后splat到两轴;
  3. 其余情况(椭圆模式)→ x 对size.x(宽度)解析、y 对size.y(高度)解析,各自钳制到[0, 0.5 * size]

同文件的单元测试corner_radius_resolve(geometry.rs)覆盖了这些行为:100x50 节点上{x: Px(100.), y: Auto}解析为vec2(25., 25.)(圆形钳制),{x: Px(40.), y: Px(40.)}解析为vec2(40., 25.)(椭圆钳制)。这也印证了BorderRadius文档中"半径若超过节点宽/高的一半,会被计算为高/宽的一半"的说明(ui_node.rs)。

BorderRadius 构造器与更新函数不再 const

迁移指南指出:BorderRadius的构造函数和更新函数不再是const,以便参数可以接受任意实现Into<CornerRadius>的类型:

let n = BorderRadius::top_right(vh(10.)); let m = BorderRadius::top_right([px(10.), px(20.)]);

实现上,allnewtop_left/top_right/bottom_right/bottom_leftleft/right/top/bottom以及with_*系列方法全部改为普通函数,参数为impl Into<CornerRadius>(ui_node.rs)。例如:

pub fn all(radius: impl Into<CornerRadius>) -> Self { let radius = radius.into(); Self { top_left: radius, top_right: radius, bottom_left: radius, bottom_right: radius, } }

两个例外值得注意:px(f32, f32, f32, f32)percent(f32, f32, f32, f32)这四个纯浮点参数的便捷构造器仍然是const fn(ui_node.rs),因为它们内部直接写CornerRadius::circular(Val::Px(...)),不经过Into转换。

BorderRadius的常量同步扩展:DEFAULT/ZERO(直角)、MAX(胶囊/圆形)、新增的MAX_ELLIPTICAL(椭圆)(ui_node.rs)。

典型写法速查

结合源码文档示例(ui_node.rs),四角混合圆角、圆角与椭圆角并存的完整写法是:

fn setup_ui(mut commands: Commands) { commands.spawn(( Node { width: Val::Px(100.), height: Val::Px(100.), border: UiRect::all(Val::Px(2.)), border_radius: BorderRadius { // 圆角,x 和 y 半径相等 top_left: CornerRadius::circular(px(10.)), // From<Val> 简写 top_right: percent(20.).into(), // 椭圆角 bottom_right: CornerRadius::new(px(30.), px(20.)), // 结构体字面量 bottom_left: CornerRadius { x: px(10.), y: px(40.) }, }, ..Default::default() }, BackgroundColor(BLUE.into()), )); }

ResolvedBorderRadius:解析结果从标量到 Vec2

ResolvedBorderRadius是渲染侧消费的解析结果。变更后(ui_node.rs):

/// The values are in physical pixels. pub struct ResolvedBorderRadius { pub top_left: Vec2, pub top_right: Vec2, pub bottom_right: Vec2, pub bottom_left: Vec2, }
  • 每个角是一个Vec2,单位为物理像素,x/y 分别对应水平/垂直半径;
  • BorderRadius::resolve只是对四角逐一调用CornerRadius::resolve(ui_node.rs),签名包含scale_factornode_sizeviewport_sizeem_sizerem_size
  • 该类型实现了From<ResolvedBorderRadius> for [[f32; 4]; 2](ui_node.rs),把四个角摊平成"第一行 4 个 x 半径、第二行 4 个 y 半径"的二维数组,从源码结构看这正是上传给 UI 渲染着色器的布局。bevy_ui_render中的节点矩形、文字、阴影等渲染模块都消费该类型。

如果你之前直接读取ResolvedBorderRadius.top_left等字段做算术(它曾是标量),需要改为访问.x/.y分量。

被移除的 API:resolve_single_corner

迁移指南最后一项:

BorderRadius::resolve_single_cornerhas been removed, useCornerRadius::resolveinstead.

即单角解析入口下移到了CornerRadius上,参数为(scale_factor, size, viewport_size, em_size, rem_size),返回该角的物理像素Vec2。需要单角数值(例如自定义裁剪矩形)时,直接对你感兴趣的那个CornerRadius字段调用resolve即可。

迁移后的真实用法验证

仓库中的示例与插件代码可以作为迁移后的参照:

  • UI 边框示例 examples/ui/styling/borders.rs 新增了四组椭圆圆角用例,同时展示了三种写法:结构体字面量CornerRadius { x: px(25), y: px(8) }、元组转换(px(8), px(25)).into()、数组转换[px(8), px(25)].into(),以及percent半径的椭圆角;
  • 控件库bevy_feathers的分段按钮圆角工具 rounded_corners.rs 中,RoundedCorners::to_border_radius通过CornerRadius::from(px(radius))构造圆角,再组合成BorderRadius——这是"旧代码用From迁移"的典型形态。

迁移检查清单

  1. BorderRadius四个角字段中的Val值包一层CornerRadius::circular(...).into()(语义等价,推荐.into()保持代码简洁);
  2. 构造器调用如BorderRadius::top_right(vh(10.))无需改动即可接受Val(Val, Val)[Val; 2]CornerRadius任意类型,需要椭圆角时传入两值即可;
  3. 若依赖了const上下文里调用all/with_*等,需改为运行期调用;纯px/percent常量构造仍可在const中使用;
  4. 读取ResolvedBorderRadius的地方改为Vec2分量运算;
  5. 删除对BorderRadius::resolve_single_corner的调用,换成对应角上的CornerRadius::resolve

完成以上步骤后,你的 UI 代码即兼容新版 Bevy 的椭圆圆角能力,并且可以随时用CornerRadius::new(px(30.), px(20.))这类写法获得 CSSborder-radius风格的多值椭圆角效果。

【免费下载链接】bevyA refreshingly simple>项目地址: https://gitcode.com/GitHub_Trending/be/bevy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 16:33:50

智慧工地一体化平台:从物联网感知到云端协同的落地实践

简介&#xff1a;这份116页PPT聚焦智慧工地系统工程&#xff0c;系统讲解基于物联网、云计算与某著名企业互联技术的建筑施工现场管理一体化平台&#xff0c;面向建筑施工企业管理人员、项目经理、智慧工地信息化建设者&#xff0c;可帮助读者快速理解智慧工地整体架构与落地路…

作者头像 李华
网站建设 2026/9/6 16:33:22

光模块产业链与封装技术解析:2023年竞争格局及核心上市公司盘点

简介&#xff1a;2023年光模块产业链竞争格局及主要上市公司分析报告&#xff0c;是一份面向光通信行业从业者、投资者及产业链研究人员的深度研究资料&#xff0c;内容覆盖从上游光芯片、无源光学元件与电子元器件&#xff0c;到中游封装设计与制造&#xff0c;再到数据中心、…

作者头像 李华
网站建设 2026/9/6 16:31:25

基于SpringBoot的大学城信息推送平台设计与实现

1. 项目背景与意义随着高校信息化建设的不断深入&#xff0c;大学城内的师生、社团、商家和后勤部门之间产生了大量碎片化信息&#xff0c;如讲座通知、社团活动、失物招领、二手交易、校园公告等。传统的信息发布方式主要依赖公告栏、QQ群、微信群和邮件&#xff0c;存在信息分…

作者头像 李华
网站建设 2026/9/6 16:29:10

Vanna 2.0 实战:自然语言生成SQL

Vanna 2.0 实战&#xff1a;自然语言生成SQL 【免费下载链接】vanna &#x1f916; Chat with your SQL database &#x1f4ca;. Accurate Text-to-SQL Generation via LLMs using Agentic Retrieval &#x1f504;. 项目地址: https://gitcode.com/GitHub_Trending/va/vann…

作者头像 李华