鴻蒙HarmonyOS實戰-ArkUI元件(Canvas)

蜀道山QAQ發表於2024-04-18

🚀一、Canvas

Canvas元件是一種圖形渲染元件,它提供了一個畫布(canvas),開發者可以在上面繪製各種圖形、文字等。Canvas元件通常用於建立遊戲、資料視覺化等需要動態繪製圖形的應用程式。

Canvas元件提供了多個API,開發者可以使用這些API進行繪製操作。常用的API包括繪製矩形、圓形、線條、文字等。開發者可以設定畫布的大小、背景色、繪製的顏色、線條的寬度等屬性。

在Canvas元件中,開發者可以監聽滑鼠事件(如點選、移動等)和鍵盤事件,以便根據使用者的互動來實現相應的操作。

Canvas元件的使用通常需要一定的程式設計知識和技巧,開發者需要了解如何使用API進行繪圖操作,以及如何處理使用者的互動事件。

🔎1.使用畫布元件繪製自定義圖形

🦋1.1 直接繪製

Canvas直接繪製圖形的原理是透過Canvas API呼叫一系列繪製方法來在Canvas元素上繪製圖形和影像。Canvas元素本身是一個空的矩形區域,透過獲取Canvas的上下文(context),可以使用上下文提供的繪製方法來進行繪製。

@Entry
@Component
struct CanvasExample1 {
  //用來配置CanvasRenderingContext2D物件的引數,包括是否開啟抗鋸齒,true表明開啟抗鋸齒。
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  //用來建立CanvasRenderingContext2D物件,透過在canvas中呼叫CanvasRenderingContext2D物件來繪製。
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      //在canvas中呼叫CanvasRenderingContext2D物件。
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#F5DC62')
        .onReady(() => {
          //可以在這裡繪製內容。
          this.context.strokeRect(50, 50, 200, 150);
        })
    }
    .width('100%')
    .height('100%')
  }
}

image

🦋1.2 離屏繪製

離屏繪製(offscreen rendering)是指將渲染結果繪製到與螢幕不直接相關的緩衝區中進行處理。傳統的渲染方式是直接將影像渲染到螢幕上,而離屏繪製則是在一個特定的緩衝區中進行渲染,然後再將渲染結果顯示到螢幕上。

離屏繪製的主要作用是實現一些特殊效果,比如陰影、模糊、遮罩等。這些效果通常需要在渲染過程中進行多次操作,直接在螢幕上渲染會導致效率低下。使用離屏繪製可以在一個獨立的緩衝區中進行這些操作,然後再將結果繪製到螢幕上。

離屏繪製可以透過一些圖形庫或引擎來實現,例如OpenGL、DirectX等。在移動裝置上,離屏繪製通常使用Frame Buffer來實現。開發者可以透過指定一個離屏渲染的目標緩衝區,然後在這個緩衝區中進行渲染操作,最後再將結果繪製到螢幕上。

離屏繪製雖然可以實現一些特殊效果,但由於需要額外的資源和計算開銷,使用不當會導致效能問題。因此,在使用離屏繪製時應該注意減少不必要的操作和資源消耗,以提高效能和使用者體驗。

@Entry
@Component
struct CanvasExample2 {
  //用來配置CanvasRenderingContext2D物件和OffscreenCanvasRenderingContext2D物件的引數,包括是否開啟抗鋸齒。true表明開啟抗鋸齒
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  //用來建立OffscreenCanvasRenderingContext2D物件,width為離屏畫布的寬度,height為離屏畫布的高度。透過在canvas中呼叫OffscreenCanvasRenderingContext2D物件來繪製。
  private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      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);
        })
    }
    .width('100%')
    .height('100%')
  }
}

image

在Canvas上載入Lottie動畫時,需要先按照如下方式下載Lottie,具體使用:https://ohpm.openharmony.cn/#/cn/detail/@ohos/lottie

🔎2.初始化畫布元件

在HarmonyOS中,Canvas類是用於繪製圖形的核心類。Canvas類提供了onReady方法,用於在Canvas準備好進行繪製之後的回撥操作。

當Canvas準備好進行繪製時,會呼叫onReady方法。開發者可以重寫onReady方法,實現一些繪製前的準備工作,例如設定畫筆顏色、繪製區域等。

要使用Canvas的onReady方法,需要建立一個Canvas例項,然後透過例項呼叫onReady方法。

@Entry
@Component
struct CanvasExample2 {
  //用來配置CanvasRenderingContext2D物件和OffscreenCanvasRenderingContext2D物件的引數,包括是否開啟抗鋸齒。true表明開啟抗鋸齒
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  //用來建立OffscreenCanvasRenderingContext2D物件,width為離屏畫布的寬度,height為離屏畫布的高度。透過在canvas中呼叫OffscreenCanvasRenderingContext2D物件來繪製。
  private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#F5DC62')
        .onReady(() => {
          this.context.fillStyle = '#0097D4';
          this.context.fillRect(50, 50, 100, 100);
        })
    }
    .width('100%')
    .height('100%')
  }
}

image

🔎3.畫布元件繪製方式

Canvas類支援使用Path2D物件來繪製複雜的路徑圖形。

Path2D是一個可重用的路徑物件,用於描述二維空間中的路徑。開發者可以使用Path2D物件來定義路徑的輪廓,並在Canvas上繪製出來。

@Entry
@Component
struct CanvasExample2 {
  //用來配置CanvasRenderingContext2D物件和OffscreenCanvasRenderingContext2D物件的引數,包括是否開啟抗鋸齒。true表明開啟抗鋸齒
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  //用來建立OffscreenCanvasRenderingContext2D物件,width為離屏畫布的寬度,height為離屏畫布的高度。透過在canvas中呼叫OffscreenCanvasRenderingContext2D物件來繪製。
  private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#F5DC62')
        .onReady(() =>{
          this.context.beginPath();
          this.context.moveTo(50, 50);
          this.context.lineTo(280, 160);
          this.context.stroke();
        })
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#F5DC62')
        .onReady(() =>{
          let region = new Path2D();
          region.arc(100, 75, 50, 0, 6.28);
          this.context.stroke(region);
        })
    }
    .width('100%')
    .height('100%')
  }
}

image

🔎4.畫布元件常用方法

image
image

🦋4.1 基礎形狀繪製

可以透過arc(繪製弧線路徑)、 ellipse(繪製一個橢圓)、rect(建立矩形路徑)等介面繪製基礎形狀

@Entry
@Component
struct CanvasExample2 {
  //用來配置CanvasRenderingContext2D物件和OffscreenCanvasRenderingContext2D物件的引數,包括是否開啟抗鋸齒。true表明開啟抗鋸齒
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  //用來建立OffscreenCanvasRenderingContext2D物件,width為離屏畫布的寬度,height為離屏畫布的高度。透過在canvas中呼叫OffscreenCanvasRenderingContext2D物件來繪製。
  private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#F5DC62')
        .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();
        })
    }
    .width('100%')
    .height('100%')
  }
}

image

🦋4.2 文字繪製

可以透過fillText(繪製填充類文字)、strokeText(繪製描邊類文字)等介面進行文字繪製。

@Entry
@Component
struct CanvasExample2 {
  //用來配置CanvasRenderingContext2D物件和OffscreenCanvasRenderingContext2D物件的引數,包括是否開啟抗鋸齒。true表明開啟抗鋸齒
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  //用來建立OffscreenCanvasRenderingContext2D物件,width為離屏畫布的寬度,height為離屏畫布的高度。透過在canvas中呼叫OffscreenCanvasRenderingContext2D物件來繪製。
  private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#F5DC62')
        .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);
        })
    }
    .width('100%')
    .height('100%')
  }
}

image

🦋4.3 繪製圖片和影像畫素資訊處理

image

@Entry
@Component
struct GetImageData {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
  private img:ImageBitmap = new ImageBitmap("1702344909275.jpg")

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#F5DC62')
        .onReady(() =>{
          // 使用drawImage介面將圖片畫在(0,0)為起點,寬高130的區域
          this.offContext.drawImage(this.img,0,0,130,130);
          // 使用getImageData介面,獲得canvas元件區域中,(50,50)為起點,寬高130範圍內的繪製內容
          let imagedata = this.offContext.getImageData(50,50,130,130);
          // 使用putImageData介面將得到的ImageData畫在起點為(150, 150)的區域中
          this.offContext.putImageData(imagedata,150,150);
          // 將離屏繪製的內容畫到canvas元件上
          let image = this.offContext.transferToImageBitmap();
          this.context.transferFromImageBitmap(image);
        })
    }
    .width('100%')
    .height('100%')
  }
}

image

🦋4.4 其他方法

Canvas中還提供其他型別的方法。漸變(CanvasGradient物件)相關的方法:createLinearGradient(建立一個線性漸變色)、createRadialGradient(建立一個徑向漸變色)等。

Canvas的createRadialGradient方法用於建立一個徑向漸變色。

語法:

createRadialGradient(x0, y0, r0, x1, y1, r1)

引數說明:

  • x0:漸變的起始圓的x座標
  • y0:漸變的起始圓的y座標
  • r0:漸變的起始圓的半徑
  • x1:漸變的結束圓的x座標
  • y1:漸變的結束圓的y座標
  • r1:漸變的結束圓的半徑
@Entry
@Component
struct GetImageData {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
  private img:ImageBitmap = new ImageBitmap("1702344909275.jpg")

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#F5DC62')
        .onReady(() =>{
          //建立一個徑向漸變色的CanvasGradient物件
          let grad = this.context.createRadialGradient(200,200,50, 200,200,200)
          //為CanvasGradient物件設定漸變斷點值,包括偏移和顏色
          grad.addColorStop(0.0, '#E87361');
          grad.addColorStop(0.5, '#FFFFF0');
          grad.addColorStop(1.0, '#BDDB69');
          //用CanvasGradient物件填充矩形
          this.context.fillStyle = grad;
          this.context.fillRect(0, 0, 400, 400);
        })
    }
    .width('100%')
    .height('100%')
  }
}

image

🔎5.場景示例

🦋5.1 規則基礎形狀繪製

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

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#F5DC62')
        .onReady(() =>{
          // 設定填充樣式,填充顏色設為藍色
          this.context.fillStyle = '#0097D4';
          // 以(50, 50)為左上頂點,畫一個寬高200的矩形
          this.context.fillRect(50,50,200,200);
          // 以(70, 70)為左上頂點,清除寬150高100的區域
          this.context.clearRect(70,70,150,100);
        })
    }
    .width('100%')
    .height('100%')
  }
}

image

🦋5.2 不規則圖形繪製

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

  build() {
    Row() {
      Column() {
        Canvas(this.context)
          .width('100%')
          .height('100%')
          .backgroundColor('#F5DC62')
          .onReady(() =>{
            // 使用Path2D的介面構造一個五邊形
            let path = new Path2D();
            path.moveTo(150, 50);
            path.lineTo(50, 150);
            path.lineTo(100, 250);
            path.lineTo(200, 250);
            path.lineTo(250, 150);
            path.closePath();
            // 設定填充色為藍色
            this.context.fillStyle = '#0097D4';
            // 使用填充的方式,將Path2D描述的五邊形繪製在canvas元件內部
            this.context.fill(path);
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

image

🚀寫在最後

  • 如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
  • 點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力。
  • 關注小編,同時可以期待後續文章ing🚀,不定期分享原創知識。
  • 更多鴻蒙最新技術知識點,請關注作者部落格:https://t.doruo.cn/14DjR1rEY
    image

相關文章