鸿蒙NEXT开发实战:图片显示、几何图形与自定义绘制详解

发布于:2025-09-04 ⋅ 阅读:(17) ⋅ 点赞:(0)

探索HarmonyOS NEXT强大的图形渲染能力,从图片展示到自定义绘图

HarmonyOS NEXT作为华为自主研发的操作系统,为开发者提供了一套丰富而强大的图形渲染能力。无论是显示图片、绘制几何图形,还是实现复杂的自定义绘图,鸿蒙都提供了简洁而高效的解决方案。

本文将详细介绍鸿蒙NEXT中三种主要的图形处理方式:图片显示、几何图形绘制和画布自定义绘制。

1. 图片显示(Image组件)

Image组件是鸿蒙中用于显示图片的核心组件,它支持多种图片格式和源类型,让开发者能够灵活地在应用中展示图像内容。

基本用法和数据源类型

Image组件支持多种数据源,只需简单调用即可显示不同来源的图片:

typescript

// 本地资源
Image('images/panda.jpg').width(100)

// Resource资源
Image($r('app.media.cat')).width(100)

// 网络资源(需要申请权限)
Image('https://example.com/example.JPG').width(200)

// 媒体库资源
Image('file://media/Photos/5').width(200)

// Base64资源
Image('data:image/png;base64,...').width(100)

// PixelMap像素图
@State image: PixelMap | undefined = undefined
Image(this.image).width(100).height(100)

网络图片权限申请

使用网络图片时,需要在module.json5文件中声明网络访问权限:

json

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}

常用属性配置

Image组件提供了一系列属性用于控制图片显示效果:

typescript

Image($r('app.media.cat'))
  .width(100)
  .height(200)
  .objectFit(ImageFit.Fill) // 设置缩放类型
  .fillColor(Color.Blue)    // 设置SVG图片的绘制颜色

objectFit属性支持多种枚举值,用于控制图片的缩放行为:

属性值 说明
ImageFit.Contain 保持宽高比进行缩小或者放大,使得图片完全显示在显示边界内
ImageFit.Cover 保持宽高比进行缩小或者放大,使得图片两边都大于或等于显示边界
ImageFit.Auto 自适应显示
ImageFit.Fill 不保持宽高比进行放大缩小,使得图片充满显示边界
ImageFit.ScaleDown 保持宽高比显示,图片缩小或者保持不变
ImageFit.None 保持原有尺寸显示

2. 绘制几何图形(Shape组件)

鸿蒙系统提供了强大的几何图形绘制能力,可以通过Shape组件及其子组件创建各种矢量图形。

创建绘制组件

绘制组件可以由以下两种形式创建:

形式一:绘制组件使用Shape作为父组件,实现类似SVG的效果。

typescript

// 创建带有父组件的绘制组件
Shape() {
  Rect().width(300).height(50)
  Circle({ width: 150, height: 150 }).fill('red')
}

形式二:绘制组件单独使用,直接在页面上绘制指定图形。

typescript

// 单独使用绘制组件
Circle({ width: 150, height: 150 })

鸿蒙提供了7种基本绘制类型:Circle(圆形)、Ellipse(椭圆形)、Line(直线)、Polyline(折线)、Polygon(多边形)、Path(路径)、Rect(矩形)。

形状视口viewport

Shape组件支持viewport属性,用于指定用户空间中的一个矩形,该矩形映射到为关联的SVG元素建立的视区边界。

typescript

Shape() {
  Rect().width(300).height(50)
}
.viewPort({
  x: 0,
  y: 0,
  width: 300,
  height: 100,
})

viewport属性包含四个可选参数:

  • x 和 y:表示视区的左上角坐标

  • width 和 height:表示视区尺寸

通过viewport可以实现图形的放大与缩小效果:

typescript

// 通过viewport对图形进行放大与缩小
Row({space:10}) {
  Column() {
    // 放大效果
    Shape() {
      Rect().width('100%').height('100%').fill('#0097D4')
      Circle({width: 75, height: 75}).fill('#E87361')
    }
    .viewPort({x: 0, y: 0, width: 75, height: 75})
    .width(150)
    .height(150)
  }
  Column() {
    // 缩小效果
    Shape() {
      Rect().width('100%').height('100%').fill('#BDDB69')
      Circle({width: 75, height: 75}).fill('#E87361')
    }
    .viewPort({x: 0, y: 0, width: 300, height: 300})
    .width(150)
    .height(150)
  }
}

自定义样式

绘制组件支持多种属性来自定义样式:

typescript

// 设置填充颜色
Path()
  .width(100)
  .height(100)
  .commands('M150 0 L300 300 L0 300 Z')
  .fill("#E87361")

// 设置边框颜色
Path()
  .width(100)
  .height(100)
  .fillOpacity(0)
  .commands('M150 0 L300 300 L0 300 Z')
  .stroke(Color.Red)

// 设置边框透明度
Path()
  .width(100)
  .height(100)
  .fillOpacity(0)
  .commands('M150 0 L300 300 L0 300 Z')
  .stroke(Color.Red)
  .strokeWidth(10)
  .strokeOpacity(0.2)

// 设置线条拐角样式
Polyline()
  .width(100)
  .height(100)
  .fillOpacity(0)
  .stroke(Color.Red)
  .strokeWidth(8)
  .points([[20, 0], [0, 100], [100, 90]])
  .strokeLineJoin(LineJoinStyle.Round) // 圆角连接

// 设置斜接长度与边框宽度比值
Polyline()
  .width(100)
  .height(100)
  .fillOpacity(0)
  .stroke(Color.Red)
  .strokeWidth(10)
  .points([[20, 0], [20, 100], [100, 100]])
  .strokeLineJoin(LineJoinStyle.Miter) // 尖角连接
  .strokeMiterLimit(1/Math.sin(45))    // 设置比值

3. 使用画布绘制自定义图形(Canvas组件)

对于更复杂的绘图需求,鸿蒙提供了Canvas组件,允许开发者进行完全自定义的图形绘制。

初始化画布组件

Canvas组件使用前需要初始化,并通过onReady事件回调进行绘制操作:

typescript

// 配置CanvasRenderingContext2D对象参数
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

// 初始化画布组件
Canvas(this.context)
  .width('100%')
  .height('100%')
  .backgroundColor('#F5DC62')
  .onReady(() => {
    // 在onReady回调中进行绘制操作
    this.context.fillStyle = '#0097D4';
    this.context.fillRect(50, 50, 100, 100);
  })

画布绘制方式

Canvas组件提供了两种绘制方式:

方式一:直接调用CanvasRenderingContext2D对象的API进行绘制

typescript

Canvas(this.context)
  .onReady(() =>{
    this.context.beginPath();
    this.context.moveTo(50, 50);
    this.context.lineTo(280, 160);
    this.context.stroke();
  })

方式二:先定义Path2D对象构造路径,再进行绘制

typescript

Canvas(this.context)
  .onReady(() =>{
    let region = new Path2D();
    region.arc(100, 75, 50, 0, 6.28);
    this.context.stroke(region);
  })

离屏绘制

离屏绘制(offscreen rendering)允许将渲染结果绘制到与屏幕不直接相关的缓冲区中进行处理,适用于实现阴影、模糊、遮罩等特殊效果。

typescript

// 离屏绘制示例
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
// 创建离屏画布上下文
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)

Canvas(this.context)
  .width('100%')
  .height('100%')
  .backgroundColor('#F5DC62')
  .onReady(() =>{
    // 在离屏画布上绘制
    this.offContext.strokeRect(50, 50, 200, 150);
    // 将离屏绘制的图像在普通画布上显示
    let image = this.offContext.transferToImageBitmap();
    this.context.transferFromImageBitmap(image);
  })

画布常用绘制方法

Canvas组件提供了丰富的API用于绘制各种图形和效果:

基础形状绘制

typescript

Canvas(this.context)
  .onReady(() =>{
    // 绘制矩形
    this.context.beginPath();
    this.context.rect(100, 50, 100, 100);
    this.context.stroke();
    
    // 绘制圆形
    this.context.beginPath();
    this.context.arc(150, 250, 50, 0, 6.28);
    this.context.stroke();
    
    // 绘制椭圆
    this.context.beginPath();
    this.context.ellipse(150, 450, 50, 100, Math.PI * 0.25, Math.PI * 0, Math.PI * 2);
    this.context.stroke();
  })

文本绘制

typescript

Canvas(this.context)
  .onReady(() =>{
    // 绘制填充类文本
    this.context.font = '50px sans-serif';
    this.context.fillText("Hello World!", 50, 100);
    
    // 绘制描边类文本
    this.context.font = '55px sans-serif';
    this.context.strokeText("Hello World!", 50, 150);
  })

渐变效果

typescript

Canvas(this.context)
  .onReady(() =>{
    // 创建径向渐变色
    let grad = this.context.createRadialGradient(200,200,50, 200,200,200)
    // 设置渐变断点值
    grad.addColorStop(0.0, '#E87361');
    grad.addColorStop(0.5, '#FFFFF0');
    grad.addColorStop(1.0, '#BDDB69');
    // 使用渐变色填充矩形
    this.context.fillStyle = grad;
    this.context.fillRect(0, 0, 400, 400);
  })

绘制图片和图像像素处理

Canvas组件还支持通过drawImage方法绘制图片,以及通过createImageData、getPixelMap、getImageData等方法进行图像像素信息处理。

实战示例:绘制一个简单的自定义图形

下面是一个综合运用Shape和Canvas组件绘制自定义图形的完整示例:

typescript

@Entry
@Component
struct CustomGraphicsExample {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

  build() {
    Column({ space: 10 }) {
      // 使用Shape组件绘制几何图形
      Shape() {
        Circle({ width: 100, height: 100 }).fill('#E87361')
        Rect().width(200).height(50).fill('#0097D4')
      }
      .viewPort({ x: 0, y: 0, width: 300, height: 150 })
      .width(300)
      .height(150)
      .backgroundColor('#F5DC62')

      // 使用Canvas组件绘制自定义图形
      Canvas(this.context)
        .width(300)
        .height(300)
        .backgroundColor('#FFFFFF')
        .onReady(() => {
          // 绘制矩形
          this.context.fillStyle = '#0097D4';
          this.context.fillRect(50, 50, 100, 100);
          
          // 绘制圆形
          this.context.beginPath();
          this.context.arc(200, 200, 50, 0, 6.28);
          this.context.fillStyle = '#E87361';
          this.context.fill();
          
          // 绘制文本
          this.context.font = '20px sans-serif';
          this.context.fillStyle = '#000000';
          this.context.fillText("HarmonyOS NEXT", 60, 250);
        })
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

总结

HarmonyOS NEXT提供了丰富而强大的图形渲染能力,从简单的图片显示到复杂的自定义绘图,都能满足开发者的各种需求:

  1. Image组件简单易用,支持多种图片源和显示效果控制,适合大多数图片展示场景。

  2. Shape组件提供了声明式的矢量图形绘制方式,支持7种基本几何图形和丰富的样式配置,适合绘制简单的矢量图形。

  3. Canvas组件提供了底层的绘图API,支持完全自定义的图形绘制,适合复杂的绘图需求和动态图形效果。

无论是开发简单的图片展示功能,还是实现复杂的自定义图形绘制,鸿蒙NEXT都能提供合适的解决方案。希望通过本文的介绍,能帮助您更好地理解和运用鸿蒙的图形渲染能力,开发出更加美观和功能丰富的应用。

温馨提示:在实际开发中,请注意根据需求选择合适的图形渲染方式。对于简单的静态图形,优先考虑使用Shape组件;对于复杂的动态图形,再考虑使用Canvas组件。同时,使用网络图片时别忘了申请相应的权限。