《鸿蒙纪元》 是 张风捷特烈 计划打造的一套 HarmonyOS 开发系列教程合集。致力于创作优质的鸿蒙原生学习资源,帮助开发者进入纯血鸿蒙的开发之中。本系列的所有代码将开源在 HarmonyUnit 项目中:
github
: github.com/toly1994328…
gitee
: gitee.com/toly1994328…
鸿蒙纪元 系列文章列表可在《文章总集》 或 【github 项目首页】 查看。
上一篇,我们完成了手势交互绘制线条的基本功能,并通过清空操作,简单了解对话框的使用。
本篇我们将继续完善画板绘制的功能,如下所示:支持 线条粗细 和 绘制颜色 的切换功能:
- | - |
---|---|
1.数据准备
首先来思考一下,完成当前功能需要额外增加哪些数据:
- [1]. 画板支持的线宽列表 supportStorkWidths ,类型 number[];
- [2]. 当前选中的线宽索引 supportColors ,类型 number;
- [3]. 画板支持的颜色列表 colorIndex,类型 string[];
- [4]. 当前选中的颜色索引 storkWidthIndex,类型 number;
于是可以在 PainterBloc
中定义如下四个与界面构建相关的变量:
---->[pages/painter/bloc/PainterBloc.ets]----
export class PainterBloc {
@Track supportStorkWidths: number[] = [1, 2, 4, 6, 8, 10];
@Track supportColors: string[] =
['#ff000000', '#fff44336', '#ffff9800', '#ffffeb3b', '#ff4caf50', '#ff2196f3', '#ff3f51b5', '#ff9c27b0', '#ffe91e63',
'#ff9e9e9e', '#ffff5252', '#ffffab40', '#ffffff00', '#ff69f0ae', '#ff448aff', '#ff536dfe', '#ffe040fb', '#ffff4081',
'#889e9e9e', '#88ff5252', '#88ffab40', '#88ffff00', '#8869f0ae', '#88448aff', '#88536dfe', '#88e040fb', '#88ff4081',
'#449e9e9e', '#44ff5252', '#44ffab40', '#44ffff00', '#4469f0ae', '#44448aff', '#44536dfe', '#44e040fb', '#44ff4081',
];
@Track colorIndex: number = 0;
@Track storkWidthIndex: number = 0;
2. 视图层交互
视图层是两个选择器,如下所示,左侧选择颜色,右侧选择线宽;选择器的功能相对独立,也有一定的可复用性,使用拆分成组件是非常合适的:
颜色选择器这里封装了 ColorSelector 组件,构建过程需要依赖的数据有 颜色列表
和 激活索引
。通过 Flex 组件对若干个颜色圈进行布局,FlexWrap.Wrap
可以让子组件在主轴方向上,超过范围时自动换行。使用 ForEach 变量构建多个条目组件。
条目具体的构建逻辑交由 circleItem 构建函数处理,基于是否选中觉顶边线样式。条目在点击时通过 onSelected
回调通知外界,并附带点击索引:
---->[pages/painter/view/ColorSelector.ets]----
type IndexSelector = (index: number) => void;
@Component
export struct ColorSelector {
@Prop activeIndex: number = 0;
private colors: string[] = [];
private onSelected?: IndexSelector;
@Builder
circleItem(color: string, index: number) {
Row() {
Shape() {Circle().fill(color).width(20).height(20)}
}
.height(28)
.width(28)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Center)
.border(index == this.activeIndex ? { width: 1.5, radius: 14, color: '#317bd4' } : { color: Color.Transparent })
.onClick(() => this.onSelected!(index));
}
build() {
Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.SpaceEvenly }) {
ForEach(this.colors, (item: string, index: number) => this.circleItem(item, index),);
}
}
}
线粗细的选择器 StorkWidthSelector 实现也是类似,传入支持的线宽列表、激活索引,以及回调函数。如下所示:
---->[pages/painter/view/LineSelector.ets]----
@Component
export struct StorkWidthSelector {
@Prop activeIndex: number = 0;
@Prop color: string = '#000000'
private stokeWidths: number[] = [];
private onSelected?: IndexSelector;
@Builder
lineItem(item: number, index: number) {
Row() {
Shape().height(item).width(64).backgroundColor(this.color)
}.height(20)
.padding({left:8,right:8})
.alignItems(VerticalAlign.Center)
.border(index == this.activeIndex ? { width: 1.5, radius: 10, color: '#317bd4' } : {color: Color.Transparent })
.onClick(() => this.onSelected!(index));
}
build() {
Column() {
ForEach(this.stokeWidths, (item: number, index: number) => this.lineItem(item, index),);
}
}
}
最后,在画板界面中通过 Stack 将两个选择器叠放在底部即可。选择器的 onSelected
回调事件,可以交由 PainterBloc
来处理。比如修改颜色,调用 model#changeColor 更新颜色索引:
3. 切换逻辑处理
切换线宽和颜色,只需要更新对应的索引即可。在业务逻辑层 PainterBloc 进行处理:
---->[pages/painter/bloc/PainterBloc.ets]----
changeStorkWidths(index: number) {
this.storkWidthIndex = index
}
changeColor(index: number) {
this.colorIndex = index
}
最后在 newLine 中,根据当前线宽和颜色索引,在添加线条时,为 Line 对象指定线宽和颜色。
- | - |
---|---|
// 开始平移时,添加新线
newLine(x: number, y: number) {
let currentColor = this.supportColors[this.colorIndex];
let currentStorkWidths = this.supportStorkWidths[this.storkWidthIndex];
this.lines.push(new Line([new Point(x, y)], currentColor, currentStorkWidths));
}
到这里就完成了本章任务,为用户提供修改颜色和线宽的操作,以便于绘制更复杂多彩的图案。这里提交一个小里程碑 v19-绘制设置线宽、颜色
尾声
从本文可以体会出:新增加一个需求,往往会引入相关的数据来实现功能。比如对于修改颜色的需求,需要引入支持的颜色列表和激活的颜色索引两个数据。所以对于任何功能需求而言,既要看其表面的界面呈现,也要分析其背后的用户交互过程中的数据变化情况。
下一章,将继续对当前的画板项目进行一些小优化,比如支持回退和撤销回退的功能;以及优化一下点集的收集策略,来尽可能地避免收录过多无用点,减小绘制的压力。
更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。关注 公众号
并回复 鸿蒙纪元 可领取最新的 xmind 脑图电子版,让我们一起成长,变得更强。我们下次再见~