鸿蒙纪·梦始卷#13 | 画板绘制 - 参数设置

234 阅读5分钟

《鸿蒙纪元》张风捷特烈 计划打造的一套 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 脑图电子版,让我们一起成长,变得更强。我们下次再见~