自定义生成图像Bitmap并实时绘制到页面布局

数据由AI生成。

功能概述

本示例演示如何在鸿蒙OS API12+中使用ArkUI实现以下功能:

  1. 自定义生成图像Bitmap

  2. 实时绘制到页面布局中

  3. 图像默认铺满所在布局

  4. 实现触摸移动图像中的点或线的操作

完整代码实现

// 导入必要的模块
import { Bitmap, PixelMap, image } from '@kit.ImageKit';
import { drawing } from '@kit.ArkGraphics2D';
import { display } from '@kit.ArkUI';

@Component
struct DrawingCanvas {
  // 定义画布尺寸
  private canvasWidth: number = 0;
  private canvasHeight: number = 0;
  
  // 定义绘制对象
  private pixelMap: PixelMap | null = null;
  private drawingContext: drawing.DrawingContext | null = null;
  
  // 定义可移动的点
  private points: Array<{ x: number, y: number }> = [
    { x: 100, y: 100 },
    { x: 200, y: 200 }
  ];
  
  // 定义选中的点索引
  private selectedPointIndex: number = -1;
  
  // 定义触摸事件处理
  private touchHandler: (event: TouchEvent) => void = (event) => {
    if (event.type === TouchType.Down || event.type === TouchType.Move) {
      const touchX = event.touches[0].x;
      const touchY = event.touches[0].y;
      
      // 检查是否点击了点
      if (event.type === TouchType.Down) {
        this.selectedPointIndex = -1;
        for (let i = 0; i < this.points.length; i++) {
          const distance = Math.sqrt(
            Math.pow(touchX - this.points[i].x, 2) + 
            Math.pow(touchY - this.points[i].y, 2)
          );
          if (distance < 30) { // 30像素的点击范围
            this.selectedPointIndex = i;
            break;
          }
        }
      }
      
      // 移动选中的点
      if (this.selectedPointIndex >= 0) {
        this.points[this.selectedPointIndex].x = touchX;
        this.points[this.selectedPointIndex].y = touchY;
        this.redrawCanvas();
      }
    }
  };
  
  // 初始化画布
  aboutToAppear() {
    // 获取屏幕尺寸
    const displayInfo = display.getDefaultDisplaySync();
    this.canvasWidth = displayInfo.width;
    this.canvasHeight = displayInfo.height;
    
    // 创建PixelMap
    this.createPixelMap();
  }
  
  // 创建PixelMap
  private createPixelMap() {
    const imageInfo: image.ImageInfo = {
      size: {
        height: this.canvasHeight,
        width: this.canvasWidth
      },
      pixelFormat: image.PixelFormat.RGBA_8888,
      alphaType: image.AlphaType.IMAGE_ALPHA_TYPE_OPAQUE
    };
    
    const initialPixels = new ArrayBuffer(this.canvasWidth * this.canvasHeight * 4);
    image.createPixelMap(imageInfo, initialPixels).then((pixelMap: PixelMap) => {
      this.pixelMap = pixelMap;
      this.redrawCanvas();
    });
  }
  
  // 重绘画布
  private redrawCanvas() {
    if (!this.pixelMap) return;
    
    // 创建DrawingContext
    drawing.createDrawingContext(this.pixelMap).then((context: drawing.DrawingContext) => {
      this.drawingContext = context;
      
      // 清空画布
      this.drawingContext.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
      
      // 绘制背景
      this.drawingContext.fillStyle = '#FFFFFF';
      this.drawingContext.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
      
      // 绘制连接线
      this.drawingContext.strokeStyle = '#0000FF';
      this.drawingContext.lineWidth = 2;
      this.drawingContext.beginPath();
      this.drawingContext.moveTo(this.points[0].x, this.points[0].y);
      this.drawingContext.lineTo(this.points[1].x, this.points[1].y);
      this.drawingContext.stroke();
      
      // 绘制点
      this.drawingContext.fillStyle = '#FF0000';
      this.points.forEach(point => {
        this.drawingContext.beginPath();
        this.drawingContext.arc(point.x, point.y, 10, 0, Math.PI * 2);
        this.drawingContext.fill();
      });
      
      // 更新UI
      this.pixelMap = this.drawingContext.getPixelMap();
    });
  }
  
  build() {
    Column() {
      // 绘制区域
      Stack() {
        // 背景层
        Column()
          .width('100%')
          .height('100%')
          .backgroundColor('#F5F5F5')
        
        // 图像层
        if (this.pixelMap) {
          Image(this.pixelMap)
            .width('100%')
            .height('100%')
            .objectFit(ImageFit.Fill)
            .onTouch(this.touchHandler)
        }
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
  }
}

@Entry
@Component
struct Index {
  build() {
    Column() {
      DrawingCanvas()
    }
    .width('100%')
    .height('100%')
  }
}

代码说明

1. 图像创建与绘制

  1. PixelMap创建

    • 使用image.createPixelMap()创建指定尺寸的PixelMap

    • 设置像素格式为RGBA_8888以获得彩色图像支持

  2. 绘图上下文

    • 通过drawing.createDrawingContext()获取绘图上下文

    • 使用标准的Canvas 2D API进行绘制操作

2. 触摸交互实现

  1. 触摸事件处理

    • 监听onTouch事件处理触摸操作

    • 检测触摸点是否在可移动点附近(30像素范围内)

    • 更新选中点的位置并重绘

  2. 点移动逻辑

    • TouchType.Down时检测是否选中点

    • TouchType.Move时更新选中点位置

3. 图像显示

  1. 布局设置

    • 使用Stack布局叠加背景和图像

    • Image组件使用objectFit(ImageFit.Fill)确保图像铺满容器

  2. 实时更新

    • 每次修改后调用redrawCanvas()重绘

    • 通过更新pixelMap触发UI刷新

扩展建议

  1. 性能优化

    • 对于复杂绘图,考虑使用OffscreenCanvas进行离屏渲染

    • 实现双缓冲技术减少闪烁

  2. 功能增强

    • 添加多点触摸支持

    • 实现线条的添加和删除功能

    • 添加撤销/重做功能

  3. 视觉效果

    • 为可移动点添加悬停效果

    • 实现平滑的动画过渡

这个示例提供了完整的实现框架,您可以根据实际需求进行修改和扩展。