【xilem0.4基础语法学与练】第55课 canvas 官方示例代码深度解析
前言源码来源xilem/examples/canvas.rs适配版本Xilem 0.4 / Masonry 0.4一、完整源码// Copyright 2024 the Xilem Authors// SPDX-License-Identifier: Apache-2.0//! An imaging recording can be used directly in Xilem.usestd::sync::atomic::{AtomicU32,Ordering};usexilem::kurbo::{Circle,Size};usexilem::masonry::imaging::{Painter,record::Scene};usexilem::peniko::Color;usexilem::view::{canvas,text_button,zstack};usexilem::winit::error::EventLoopError;usexilem::{EventLoop,WidgetView,WindowOptions,Xilem};/// Simple but suboptimal pseudo-random function, you shouldnt use this in productionfnrand_f32()-f32{staticSEED:AtomicU32AtomicU32::new(123);SEED.fetch_update(Ordering::Relaxed,Ordering::Relaxed,|x|{Some(x.wrapping_mul(1664525).wrapping_add(1013904223))}).unwrap()asf32*(1.0/u32::MAXasf32)}#[derive(Default)]structCircles{circles:Vec(Circle,Color),current_canvas_size:Size,}implCircles{fnpush_random_circle(mutself){letposition(rand_f32()asf64*self.current_canvas_size.width,rand_f32()asf64*self.current_canvas_size.height,);letradiusrand_f32()asf64*self.current_canvas_size.height/2.0;letcolorColor::new([rand_f32(),rand_f32(),rand_f32(),1.0]);self.circles.push((Circle::new(position,radius),color));}fnview(mutself)-implWidgetViewSelfuse{zstack((canvas(|state:mutSelf,_ctx,scene:mutScene,size:Size|{letmutpainterPainter::new(scene);for(circle,color)instate.circles{painter.fill(*circle,*color).draw();}state.current_canvas_sizesize;}),text_button(Add Circle,Self::push_random_circle),))}}fnmain()-Result(),EventLoopError{Xilem::new_simple(Circles::default(),Circles::view,WindowOptions::new(Canvas - Circles),).run_in(EventLoop::with_user_event())}二、程序核心功能本课主题canvas自定义画布绘图 zstack图层叠加Xilem矢量绘图基础画布底层基于Masonry imaging、kurbo几何库、peniko色彩库点击 Add Circle 按钮在画布随机位置生成随机大小、随机RGB颜色的圆形画布会记录窗口尺寸新生成圆不会超出画布范围使用 zstack 图层容器底层canvas画布上层叠加按钮按钮悬浮在画布之上核心概念canvas 自定义绘图组件回调函数里执行绘制逻辑zstack 层叠布局Z轴堆叠后放元素在上层kurbo几何图形库Circle、Rect、Line等矢量形状peniko颜色、画笔样式库Scene Painter Masonry的绘图录制API先录制绘制指令再统一交给Vello渲染三、逐模块深度解析1. rand_f32 简易伪随机函数fnrand_f32()-f32{staticSEED:AtomicU32AtomicU32::new(123);SEED.fetch_update(Ordering::Relaxed,Ordering::Relaxed,|x|{Some(x.wrapping_mul(1664525).wrapping_add(1013904223))}).unwrap()asf32*(1.0/u32::MAXasf32)}使用静态原子变量 AtomicU32 保存种子线程安全LCG线性同余算法生成0~1之间的浮点数⚠️注释提示仅演示生产环境不要使用这个简易随机数2. 数据模型 Circles#[derive(Default)]structCircles{circles:Vec(Circle,Color),// 存储所有圆几何图形 颜色current_canvas_size:Size,// 记录画布当前宽高}Circle 来自kurbo包含圆心坐标半径Size kurbo类型width/height保存画布尺寸fnpush_random_circle(mutself){letposition(rand_f32()asf64*self.current_canvas_size.width,rand_f32()asf64*self.current_canvas_size.height,);letradiusrand_f32()asf64*self.current_canvas_size.height/2.0;letcolorColor::new([rand_f32(),rand_f32(),rand_f32(),1.0]);self.circles.push((Circle::new(position,radius),color));}生成随机圆心、随机半径、随机RGB颜色Alpha1不透明存入circles数组。3. view方法zstack canvas本课重点fnview(mutself)-implWidgetViewSelfuse{zstack((canvas(|state:mutSelf,_ctx,scene:mutScene,size:Size|{letmutpainterPainter::new(scene);for(circle,color)instate.circles{painter.fill(*circle,*color).draw();}state.current_canvas_sizesize;}),text_button(Add Circle,Self::push_random_circle),))}zstackZ方向堆叠布局先写的元素在底层后写的在上层底层canvas画布上层Add Circle按钮悬浮在画布上面可点击canvas回调参数state: mut Self 应用状态_ctx 绘图上下文scene: mut Scene 绘图录制场景所有绘制操作先记录到scenesize: Size 当前canvas画布尺寸Painter 画笔painter.fill(图形, 颜色).draw() 填充图形遍历所有保存的圆逐个绘制把当前画布size存入state新增圆形时以此作为边界4. main入口fnmain()-Result(),EventLoopError{Xilem::new_simple(Circles::default(),Circles::view,WindowOptions::new(Canvas - Circles),).run_in(EventLoop::with_user_event())}这里使用实例方法作为view逻辑 Circles::view 是Xilem另一种组织代码的写法和单独写 app_logic 函数效果等价。四、数据流初始化Circles默认circles为空数组画布尺寸初始0,0窗口渲染canvas回调执行遍历circles绘制圆形一开始无图形点击Add Circle执行 push_random_circle 生成随机圆存入数组并读取当前画布尺寸状态变更 → 重新执行viewcanvas回调再次执行遍历数组绘制全部圆形窗口缩放时canvas回调会拿到新size并更新 current_canvas_size五、本课核心知识点总结canvas组件用于自定义矢量绘图绘图逻辑写在回调内绘图是录制到Scene由Vello渲染引擎绘制。zstack Z轴堆叠布局元素前后叠加适合画布悬浮控件场景。配套生态库kurbo2D几何Circle、Rect、Line、Bezier曲线peniko颜色、画笔、渐变Painter绘图画笔fill填充、stroke描边最后调用 .draw() 提交绘制指令代码组织方式可以把 view 作为结构体impl的成员方法不必单独写app_logic函数。Atomic原子类型实现无锁全局状态生成随机种子。六、课后习题练习1 填空zstack 是____布局实现元素前后叠加。Xilem canvas绘图回调中所有绘制指令先写入____。几何圆形 Circle 来自____库。Painter的 fill 方法用来____图形。参考答案Z轴堆叠Scenekurbo填充练习2 判断zstack中写在前面的组件渲染在底层。✅正确canvas回调只会在点击按钮的时候执行。❌错误窗口缩放、重绘都会触发peniko的Color支持RGBA。✅正确示例里的rand_f32是生产环境推荐的随机算法。❌错误仅演示用练习3 简答题目canvas绘图和普通flex/label/button组件最大区别是什么参考答案普通组件是框架内置封装好的UI元素直接链式调用配置属性canvas是原始绘图画布开发者在回调中使用画笔手动描述矢量图形圆、线条、矩形等完全自定义绘制内容自由度更高。