当前位置: 首页 > news >正文

HarmonyOS APP实战-画图APP - 第3篇:矩形与圆形绘制

HarmonyOS APP实战-画图APP - 第3篇:实现基本形状绘制

1. 开篇

上一篇我们完成了画图APP的主页面布局,构建了顶部工具栏、底部颜色选择栏和中间画布区域的基础框架。顶部工具栏预留了形状切换按钮,底部颜色栏提供了基本的颜色选项,画布区域能够响应触摸事件并显示触摸坐标。页面整体交互骨架已经建立,但画布还无法真正绘制图形。

本篇将在现有框架上注入绘制能力。我们将使用@ohos.graphics.drawing模块提供的自绘制API,实现矩形、正方形和圆形的绘制功能。具体包括:通过触摸事件的按下和抬起位置确定形状的包围盒,调用drawRectdrawCircleAPI进行实际绘制,并支持底部颜色选择栏改变填充颜色。完成后,点击工具栏的形状按钮,在画布上拖拽就能生成对应的几何图形。

2. 核心实现

2.1 基础配置 — 建立绘制模块依赖与初始化

在画图APP的工程目录下,我们需要新建一个专门的绘制工具模块,用于封装所有图形绘制逻辑。同时配置Canvas组件和@ohos.graphics.drawing相关的导入。

创建ShapeDrawer.ets文件:

// ShapeDrawer.ets// 本模块封装矩形、圆形等基本形状的绘制方法// 依赖 @ohos.graphics.drawing 库中的 Canvas 和画笔相关类import{Canvas,Brush,Pen,Point,Rect}from'@ohos.graphics.drawing';// Canvas: 画布对象,所有绘制操作基于它进行// Brush: 填充画笔,用于设置填充颜色、透明度等// Pen: 描边画笔,用于设置线条颜色、宽度等// Point: 坐标点对象// Rect: 矩形区域对象exportclassShapeDrawer{privatecanvas:Canvas|null=null;/** * 初始化绘制器,绑定画布实例 * @param canvas - 由 @ohos.graphics.drawing 创建的 Canvas 对象 */publicinit(canvas:Canvas):void{this.canvas=canvas;console.info('[ShapeDrawer] Canvas初始化完成');}/** * 绘制填充矩形 * @param left - 矩形左上角x坐标 * @param top - 矩形左上角y坐标 * @param width - 矩形宽度 * @param height - 矩形高度 * @param color - 填充颜色,格式为RGB十六进制字符串,如 '#FF0000' */publicdrawFillRect(left:number,top:number,width:number,height:number,color:string):void{if(!this.canvas){console.error('[ShapeDrawer] Canvas未初始化');return;}// 创建填充画笔Brush,设置颜色constbrush=newBrush();brush.setColor(this.parseColor(color));// 创建矩形区域对象,使用左上角坐标和宽高constrect=newRect(left,top,left+width,top+height);// 保存当前画布状态,避免后续操作污染this.canvas.save();// 设置Brush为绘制填充时使用的画笔this.canvas.attachBrush(brush);// 调用drawRect绘制填充矩形this.canvas.drawRect(rect);// 分离画笔,恢复画布状态this.canvas.detachBrush();this.canvas.restore();console.info(`[ShapeDrawer] 绘制矩形: left=${left}, top=${top}, w=${width}, h=${height}, color=${color}`);}/** * 绘制填充圆形 * @param cx - 圆心x坐标 * @param cy - 圆心y坐标 * @param radius - 圆半径 * @param color - 填充颜色 */publicdrawFillCircle(cx:number,cy:number,radius:number,color:string):void{if(!this.canvas){console.error('[ShapeDrawer] Canvas未初始化');return;}constbrush=newBrush();brush.setColor(this.parseColor(color));this.canvas.save();this.canvas.attachBrush(brush);// 使用drawCircle API绘制圆形// 参数依次为:圆心坐标点、半径、描边画笔(传null使用填充)、填充画笔this.canvas.drawCircle(newPoint(cx,cy),// 圆心坐标null,// Pen描边画笔,不需要轮廓brush// Brush填充画笔);this.canvas.detachBrush();this.canvas.restore();console.info(`[ShapeDrawer] 绘制圆形: cx=${cx}, cy=${cy}, r=${radius}, color=${color}`);}/** * 将十六进制颜色字符串转为Color对象 * @param hex - 十六进制颜色值 * @returns Color对象 */privateparseColor(hex:string):Color{// 兼容带#前缀的颜色值constcolorStr=hex.startsWith('#')?hex.substring(1):hex;// 支持6位标准色和3位简写色if(colorStr.length===3){constr=parseInt(colorStr[0]+colorStr[0],16);constg=parseInt(colorStr[1]+colorStr[1],16);constb=parseInt(colorStr[2]+colorStr[2],16);returnnewColor(r,g,b,255);}elseif(colorStr.length===6){constr=parseInt(colorStr.substring(0,2),16);constg=parseInt(colorStr.substring(2,4),16);constb=parseInt(colorStr.substring(4,6),16);returnnewColor(r,g,b,255);}// 默认返回白色returnnewColor(255,255,255,255);}}

关键点说明:

  • 使用@ohos.graphics.drawing中的CanvasBrushPenPointRect类。这是 ArkGraphics 2D 提供自绘能力的核心模块。
  • Brush.setColor方法接受Color对象,我们需要将常用的十六进制颜色字符串转为Color
  • drawRect接收一个Rect对象定义矩形区域。
  • drawCircle的签名比较特殊:第一个参数是Point圆心坐标,第二个是Pen(描边画笔,传入null表示不描边),第三个是Brush(填充画笔)。注意参数顺序和类型。
  • 每次绘制前后调用save()attachBrush()detachBrush()restore()是常规操作模式,确保不同绘制之间不会互相影响状态。

2.2 核心逻辑 — 实现触摸绘制形状的交互

现在进入画布页面的核心绘制逻辑。我们需要在上一篇文章建立的DrawingCanvas组件中,捕获用户的触摸事件,根据按下的起始点和抬起时的终点确定图形的尺寸和位置,然后调用ShapeDrawer进行绘制。

DrawingCanvas.ets中实现触摸绘制逻辑:

// DrawingCanvas.ets// 画布绘制组件,实现触摸手势绘制矩形和圆形import{Canvas,Brush,Pen,Point,Rect}from'@ohos.graphics.drawing';import{ShapeDrawer}from'./ShapeDrawer';@Componentexportstruct DrawingCanvas{// 当前选择的绘制模式:'rect' | 'circle' | 'square'@PropshapeType:string='rect';// 当前选中的颜色值@PropcurrentColor:string='#FF0000';// 触摸起始坐标privatestartX:number=0;privatestartY:number=0;// 触摸结束坐标privateendX:number=0;privateendY:number=0;// 画布引用,用于privatecanvasRef:Canvas|null=null;// 绘制工具实例privatedrawer:ShapeDrawer=newShapeDrawer();build(){Column(){// 画布区域Canvas().width('100%').height('100%').backgroundColor('#FFFFFF').onReady(()=>{// Canvas组件渲染完成时获取Canvas实例// 实际项目中需要通过Canvas组件的onReady回调获取绘图上下文// 这里简化处理,假设this.canvasRef已正确赋值if(this.canvasRef){this.drawer.init(this.canvasRef);}}).onTouch((event:TouchEvent)=>{this.handleCanvasTouch(event);})}.width('100%').height('100%')}/** * 处理画布上的触摸事件 * 按下时记录起始点,抬起时根据形状类型绘制 */privatehandleCanvasTouch(event:TouchEvent):void{consttouchInfo=event.getTouches()[0];if(!touchInfo){return;}constx=touchInfo.x;consty=touchInfo.y;if(event.type===TouchType.Down){// 记录按下位置this.startX=x;this.startY=y;console.info(`[DrawingCanvas] 触摸按下: (${x},${y})`);}elseif(event.type===TouchType.Up){// 记录抬起位置this.endX=x;this.endY=y;// 计算形状的包围盒参数constleft=Math.min(this.startX,this.endX);consttop=Math.min(this.startY,this.endY);constwidth=Math.abs(this.endX-this.startX);constheight=Math.abs(this.endY-this.startY);console.info(`[DrawingCanvas] 触摸抬起: (${this.endX},${this.endY})`);// 根据当前选中的形状类型执行绘制switch(this.shapeType){case'rect':this.drawer.drawFillRect(left,top,width,height,this.currentColor);break;case'square':// 正方形:取宽高中的较大者,使长宽相等constside=Math.max(width,height);this.drawer.drawFillRect(left,top,side,side,this.currentColor);break;case'circle':// 圆形:计算圆心坐标和半径constcx=(this.startX+this.endX)/2;constcy=(this.startY+this.endY)/2;constradius=Math.max(width,height)/2;this.drawer.drawFillCircle(cx,cy,radius,this.currentColor);break;default:console.warn(`[DrawingCanvas] 未知的形状类型:${this.shapeType}`);}}}}

关键点说明:

  • onTouch事件处理器在每次触摸时都会触发,通过event.type判断是按下(TouchType.Down)还是抬起(TouchType.Up)。
  • 绘制时用Math.minMath.abs计算包围盒,确保无论用户从哪个方向拖拽,都能正确圈出区域。
  • 正方形模式强制宽高相等,取用户拖拽范围的较大边长。
  • 圆形模式使用拖拽范围的包围盒对角线,以中心点为圆心进行计算。
  • this.canvasRef的获取在onReady回调中,这是获取 Canvas 上下文的标准方式。实际项目中这里需要更详细的初始化和上下文创建,为了示例清晰做了简化。

2.3 完整模块 — 集成绘制与页面传参

最后,我们需要将绘制模块和主页面进行完整集成。主页面Index.ets需要传递用户选择的形状类型和颜色值到DrawingCanvas组件,并触发重新绘制。以下是一个集成后的完整主页面代码。

Index.ets中集成绘制功能:

// Index.ets// 画图APP主页面,集成顶部工具栏、底部颜色栏和画布绘制区域import{DrawingCanvas}from'./DrawingCanvas';@Entry@Componentstruct Index{// 当前绘制模式:'rect' | 'circle' | 'square'@StatecurrentShape:string='rect';// 当前选中的颜色,初始为红色@StatecurrentColor:string='#FF0000';build(){Column(){// ========== 顶部工具栏 ==========Row(){// 矩形按钮Button('矩形').onClick(()=>{this.currentShape='rect';console.info(`[Index] 切换到矩形绘制模式`);})// 正方形按钮Button('正方形').onClick(()=>{this.currentShape='square';console.info(`[Index] 切换到正方形绘制模式`);})// 圆形按钮Button('圆形').onClick(()=>{this.currentShape='circle';console.info(`[Index] 切换到圆形绘制模式`);})}.width('100%').padding({left:10,right:10}).backgroundColor('#F0F0F0')// ========== 画布绘制区域 ==========DrawingCanvas({shapeType:$currentShape,currentColor:$currentColor}).layoutWeight(1)// ========== 底部颜色选择栏 ==========Row(){// 六个常用颜色按钮this.colorButton('#FF0000','红色')this.colorButton('#00FF00','绿色')this.colorButton('#0000FF','蓝色')this.colorButton('#FFFF00','黄色')this.colorButton('#FF00FF','紫色')this.colorButton('#000000','黑色')}.width('100%').padding({top:10,bottom:10}).backgroundColor('#333333').justifyContent(FlexAlign.SpaceEvenly)}.width('100%').height('100%').backgroundColor('#E0E0E0')}/** * 底部颜色按钮构建方法 * @param color - 颜色值 * @param label - 按钮文字 */@BuildercolorButton(color:string,label:string){Column(){Circle().width(40).height(40).fill(color).margin({bottom:4})Text(label).fontSize(10).fontColor('#FFFFFF')}.onClick(()=>{this.currentColor=color;console.info(`[Index] 选中颜色:${label}(${color})`);})}}

关键点说明:

  • 主页面通过@State装饰器响应式管理currentShapecurrentColor状态。
  • 点击顶部形状按钮时更新currentShape,通过$currentShape语法将状态同步到子组件DrawingCanvas
  • 底部颜色栏设计为Circle组件加文字标签,点击时更新currentColor
  • Circle是内置组件,用于显示预设颜色的色块,方便用户选择。
  • DrawingCanvas接收这些参数后,在触摸抬起时根据当前形状和颜色绘制对应图形。

3. 运行验证

在 DevEco Studio 中运行项目,预期表现如下:

  1. 启动 APP,看到熟悉的顶部工具栏、白色画布和底部颜色栏。
  2. 点击顶部的“矩形”按钮(未高亮显示为选中态,下一篇将完善交互反馈),然后在画布上从左上方到右下方拖拽手指。抬起手指后,画布上应该出现一个红色的填充矩形,且矩形区域正好覆盖你拖拽的范围。
  3. 点击“正方形”按钮,再拖拽一个任意矩形区域,画布上应该出现一个以较长边为边长的正方形。
  4. 点击“圆形”按钮,拖拽后画布上生成一个填充圆形,其直径等于拖拽范围的较长边。
  5. 点击底部颜色栏的“绿色”按钮,再绘制一个矩形,新矩形的填充色变为绿色,且不影响之前绘制的红色矩形。

4. 小结与预告

本篇在现有画布基础上,成功实现了基本形状的绘制功能。核心是创建了ShapeDrawer工具模块,封装了基于@ohos.graphics.drawingdrawRectdrawCircleAPI;并在DrawingCanvas组件中集成了触摸事件处理,根据用户拖拽范围生成矩形、正方形和圆形;同时后台颜色栏的状态已经可以影响绘制填充色,虽然当前仅支持6种固定颜色。这些功能为画图APP打下了最基础的绘制能力,后续所有高级功能都将建立在这个绘制管道之上。

下一篇将聚焦“实现触摸手绘功能”。我们会脱离预定义形状,允许用户像真正的画笔一样自由绘制轨迹。逻辑上需要记录连续的触摸点,利用Path对象和drawPathAPI 实现平滑的曲线渲染。届时,画图APP将同时支持“几何形状绘制”和“自由手绘”两种模式。

http://www.jsqmd.com/news/1177893/

相关文章:

  • 2026最新宜昌本地漏水检测公司本地精选权威推荐:正规防水补漏公司优选口碑TOP5:卫生间/厨房/阳台/飘窗/地下室渗漏水维修师傅上门 - 即刻修防水
  • 深入理解Linux多线程互斥锁:从临界区到底层原子指令的完整闭环
  • 2026年7月最新绍兴美度官方售后热线及客户服务网点地址 - 亨得利钟表维修中心
  • GitHub开源神器Zhubuntu:浏览器运行真实安卓级桌面系统
  • AirSim 1.8.1 Windows 配置:3个典型CMake与VS版本兼容性错误深度解析
  • PromQL 实战:5分钟构建3个核心监控告警规则(附HTTP API调用)
  • 3分钟解锁AMD Ryzen处理器的终极调试能力:SMUDebugTool完全指南
  • LangChain 1.3 AI Agent开发实战:从入门到企业级应用部署
  • AI投资代理实战:多智能体架构实现146%收益的技术解析
  • 5MB轻量级C盘清理工具:免费解决Windows系统空间不足问题
  • HarmonyOS APP实战-画图APP - 第6篇:形状切换与UI优化
  • LangGraph与Agentic RAG:构建智能决策的大模型应用实战
  • 2026年中湖南地区专业豆包关键词优化机构综合能力解析 - 品牌鉴赏官2026
  • AI音乐生成实战:从提示词设计到完整作品导出的SeedMusic全流程指南
  • 市面上比较实用的财务岗位证书
  • TS2007FC与PIC32MZ2048EFH100音频系统设计与优化
  • 单片机为什么能够运行神经网络?从 C 函数理解 AI推理
  • AI龙虾智能体排名
  • Elasticsearch 8.x IK分词器 3种安装方式对比:离线/在线/Docker 部署实测
  • Linux日志排查实战:从基础命令到生产环境故障定位
  • CRC 循环冗余校验码:3 步手算与 Python 实现验证
  • 【Midjourney插画风格黄金组合】:2024最新8组经实测ROI超4.2的“风格×主题×媒介”三角模型
  • 多维聚合实战:维度语义、度量量纲与动态切片技术
  • 如何一键获取国家中小学智慧教育平台电子教材:tchMaterial-parser终极指南
  • PHP代码审计基础——面向对象(四)
  • 利用Codex AI工具半小时高效完成技术论文初稿的完整指南
  • 电容失效分析
  • 几何算法实战:PAT L3-009 最少监视点问题,3种常见错误分析
  • GetQzonehistory:让QQ空间记忆永存的Python工具
  • 2026 年现阶段应城可靠的洋葱去皮机平台推荐,别再手动剥了!这个神器如何解放你的厨房双手 - 行业推荐官[官方】--