天天看點

HarmonyOS —— Image元件和ImageAnimator元件

本節首先解決@Extend裝飾器無法多頁面複用的問題,介紹通過自定義元件實作标題和正文的樣式複用。然後介紹圖檔展示元件Image和幀動畫元件ImageAnimator,并同時講解如何對圖檔應用圖像效果及實作共享元素轉場。

3.3.1 建立多頁面可複用的元件

在《3.1.1 Text元件》這節中,我們使用了@Extend裝飾器定義了title和body,實作快速定義并複用元件的自定義樣式。但是,@Extend裝飾器隻能應用在定義該裝飾器的頁面裡,無法通過export共享給其它頁面調用。同時,如果在其它頁面定義了同名的裝飾器,如,另一個頁面也定義了一個名為"title"或"body"的裝飾器,會編譯異常,提示重複的定義。

本小節建立兩個自定義元件,解決@Extend裝飾器的上述不足,實作多頁面複用。其中:

@Component裝飾的struct表示該結構體具有元件化能力,能夠成為一個獨立的元件,這種類型的元件也稱為自定義元件。

本小節不打算展開對@Component裝飾器的講解,更多的聲明式文法将在《第8章 基于TS擴充的聲明式開發規範》中講解。

在index.ets頁面底部加入如下代碼:

/**
 * H8标題
 */
@Component
export struct H8 {
  private text: string = ''
  private color: any = $r('app.color.fgLevel1')

  build() {
    Text(this.text)
      .fontSize($r('app.float.fontSizeH8'))
      .fontWeight(Number($r('app.float.fontWeightH8')))
      .fontColor(this.color)
      .fontFamily('sans-serif-condensed, sans-serif')
  }
}

/**
 * 正文文本
 */
@Component
export struct TextBody1 {
  private text: string = ''
  private color: any = $r('app.color.fgLevel1')

  build() {
    Text(this.text)
      .fontSize($r('app.float.fontSizeBody1'))
      .fontWeight(Number($r('app.float.fontWeightBody1')))
      .fontColor(this.color)
      .fontFamily('sans-serif-condensed, sans-serif')
  }
}
           

在下一小節示範如何引用并使用标題元件和正文元件。

3.3.2 Image元件

圖檔元件Image,用來渲染展示圖檔。

首先,建立ImageSample.ets頁面,用于展示本小節的效果,初始化代碼如下:

// 引用自定義元件
import {H8,TextBody1} from './index'

/**
 * 3.3.1 Image元件
 */
@Entry
@Component
struct ImageSample {
  build() {
    Stack({ alignContent: Alignment.TopStart }){
      Scroll() {
        Column({space:8}){
          // 傳回首頁
          Row({space:8}){
            Image($r("app.media.ic_back")).width(24).height(24)

            Navigator({ target: 'pages/index', type: NavigationType.Back }) {
              H8({text:'傳回'}) // 調用自定義元件
            }
          }

          // TODO

        }.padding({left: $r('app.float.spaceLeft'), right: $r('app.float.spaceRight')}).alignItems(HorizontalAlign.Start)
      }
    }.width('100%').height('100%').backgroundColor($r("app.color.appBg")).padding({top:$r('app.float.spaceTop'), bottom:$r('app.float.spaceBottom')})
  }
}
           
1.接口:Image(src: string | PixelMap)

src:string|PixelMap 圖檔的URI,支援本地圖檔和網絡路徑,支援使用媒體PixelMap對象。

PixelMap:圖像像素類,用于讀取或寫入圖像資料以及擷取圖像資訊。在調用PixelMap的方法前,需要先通過createPixelMap建立一個PixelMap執行個體。關于建立PixelMap執行個體的方法并不适合初學者學習,這裡暫時不展開讨論,後面會有專門的章節詳細講解。本專欄教程是由淺入深、循序漸進、水到渠成的。

這裡先示範如何通過接口引用App本地圖檔。圖檔格式支援“png/jpg/gif/svg”,圖檔檔案可以存放在media媒體目錄、rawfile目錄或自己建立的“/common/images”目錄。圖檔格式和圖檔存放目錄沒有對應關系,下面示範做了個随機配置設定,便于用最少代碼做更全面的示範。

在上述初始化代碼的”TODO“處加入如下代碼:

/**
           * 接口:Image(src: string | PixelMap)
           *    src:string|PixelMap 圖檔的URI,支援本地圖檔和網絡路徑,支援使用媒體PixelMap對象。
           *        PixelMap:圖像像素類,用于讀取或寫入圖像資料以及擷取圖像資訊。在調用PixelMap的方法前,需要先通過createPixelMap建立一個PixelMap執行個體。
           */
          H8({text:'1.接口'})
          TextBody1({text:'png格式圖檔,media目錄'})
          Image($r("app.media.cover")) // media目錄下的媒體資源
            .width("100%")
            .aspectRatio(1.5)
            .borderRadius($r("app.float.radius_L"))
          TextBody1({text:'gif格式圖檔,rawfile目錄'})
          Image($rawfile("ic_gif.gif")) // $rawfile資源要寫檔案字尾
            .width("100%")
            .aspectRatio(1.5)
            .borderRadius($r("app.float.radius_L"))
          TextBody1({text:'jpg格式圖檔,/common/images目錄'})
          Image("/common/images/banner.jpg") // /common/images目錄下的圖檔
            .width("100%")
            .aspectRatio(3.5)
           

在手機淺色模式和平闆深色模式下效果如下:

HarmonyOS —— Image元件和ImageAnimator元件
使用網絡路徑

如果圖檔來源于網絡,接口還是和上面一樣,但是需要在config.json檔案中“js”節點的後面加入如下配置:

"reqPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
           

如下圖所示:

HarmonyOS —— Image元件和ImageAnimator元件

然後在ImageSample.ets頁面加入如下代碼:

TextBody1({text:'svg格式圖檔,使用網絡路徑'})
          Image("https://developer.huawei.com/images/new-content/Navigation/HW-LOGO.svg") // 使用網絡路徑的圖檔
            .width(300).height(65) // Logo指定寬高,不進行自适應縮放
           

效果如下:

HarmonyOS —— Image元件和ImageAnimator元件
2.屬性

.alt(string | PixelMap): 加載時顯示的占位圖。支援本地圖檔和網絡路徑,支援使用媒體PixelMap對象。

示例代碼:

H8({text:'2.屬性'})
          /**
           * .alt(string | PixelMap): 加載時顯示的占位圖。支援本地圖檔和網絡路徑,支援使用媒體PixelMap對象。
           */
          TextBody1({text:'.alt(string | PixelMap): 加載時顯示的占位圖'})
          Image('') // 這裡使用網絡路徑的圖檔
            .width("100%")
            .aspectRatio(3.5)
            .alt($r('app.media.alt')) // 加載時顯示的占位圖
           

在媒體檔案夾下放入alt.png圖檔,淺色模式和深色模式下效果如下:

HarmonyOS —— Image元件和ImageAnimator元件

. objectFit (ImageFit): 設定圖檔的縮放類型。

示例代碼:

/**
           * .objectFit(ImageFit) 預設值Cover,設定圖檔的縮放類型。
           *    ImageFit.Cover 保持寬高比進行縮小或者放大,使得圖檔兩邊都大于或等于顯示邊界。
           *    ImageFit.Contain 保持寬高比進行縮小或者放大,使得圖檔完全顯示在顯示邊界内。
           *    ImageFit.Fill 不保持寬高比進行放大縮小,使得圖檔填充滿顯示邊界。
           *    ImageFit.None 保持原有尺寸顯示。通常配合objectRepeat屬性一起使用。
           *    ImageFit.ScaleDown 保持寬高比顯示,圖檔縮小或者保持不變。
           */
          TextBody1({text:'.objectFit(ImageFit):設定圖檔的縮放類型'})
          Image($r("app.media.cover"))
            .width('100%').height(120)
            .objectFit(ImageFit.Cover)
          Image($r("app.media.cover"))
            .width('100%').height(120)
            .objectFit(ImageFit.Contain)
          Image($r("app.media.cover"))
            .width('100%').height(120)
            .objectFit(ImageFit.Fill)
          Image($r("app.media.cover"))
            .width('100%').height(120)
            .objectFit(ImageFit.None)
          Image($r("app.media.cover"))
            .width('100%').height(120)
            .objectFit(ImageFit.ScaleDown)
           

在手機和平闆上,圖檔表現如下:

HarmonyOS —— Image元件和ImageAnimator元件

. objectRepeat (ImageRepeat): 設定圖檔的重複樣式。

示例代碼:

/**
           * .objectRepeat (ImageRepeat): 預設值NoRepeat,設定圖檔的重複樣式。
           *    ImageRepeat.X 隻在水準軸上重複繪制圖檔。
           *    ImageRepeat.Y 隻在豎直軸上重複繪制圖檔。
           *    ImageRepeat.XY 在兩個軸上重複繪制圖檔。
           *    ImageRepeat.NoRepeat 不重複繪制圖檔。
           * 注意:SVG類型圖源不支援該屬性。
           */
          TextBody1({text:'. objectRepeat (ImageRepeat): 設定圖檔的重複樣式'})
          Image($r('app.media.icon'))
            .width(115).height(115)
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.ScaleDown)
            .objectRepeat(ImageRepeat.X) // 隻在水準軸上重複繪制圖檔
          Image($r('app.media.icon'))
            .width(115).height(115)
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.ScaleDown)
            .objectRepeat(ImageRepeat.Y) // 隻在豎直軸上重複繪制圖檔
          Image($r('app.media.icon'))
            .width(115).height(115)
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.ScaleDown)
            .objectRepeat(ImageRepeat.XY) // 在兩個軸上重複繪制圖檔
          Image($r('app.media.icon'))
            .width(115).height(115)
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.ScaleDown)
            .objectRepeat(ImageRepeat.NoRepeat) // 不重複繪制圖檔
           

運作效果:

HarmonyOS —— Image元件和ImageAnimator元件

. interpolation (ImageInterpolation): 設定圖檔的插值效果,僅針對圖檔放大插值。

對于一些較小的圖檔,或老照片,插值計算有助于提升畫質。示例代碼:

/**
           * .interpolation (ImageInterpolation): 設定圖檔的插值效果,僅針對圖檔放大插值。預設值None。
           *    ImageInterpolation.None 不使用插值圖檔資料。
           *    ImageInterpolation.High 高度使用插值圖檔資料,可能會影響圖檔渲染的速度。
           *    ImageInterpolation.Medium 中度使用插值圖檔資料。
           *    ImageInterpolation.Low 低度使用插值圖檔資料。
           * 注意:SVG類型圖源不支援該屬性;PixelMap資源不支援該屬性。
           */
		  TextBody1({text:'.interpolation (ImageInterpolation): 設定圖檔的插值效果'})
          Image('/common/images/photo.png')
            .width(300)
            .objectFit(ImageFit.Cover)
            .interpolation (ImageInterpolation.None) // 不使用插值圖檔資料
          Image('/common/images/photo.png')
            .width(300)
            .objectFit(ImageFit.Cover)
            .interpolation (ImageInterpolation.High) // 高度使用插值圖檔資料
          Image('/common/images/photo.png')
            .width(300)
            .objectFit(ImageFit.Cover)
            .interpolation (ImageInterpolation.Medium) // 中度使用插值圖檔資料
          Image('/common/images/photo.png')
            .width(300)
            .objectFit(ImageFit.Cover)
            .interpolation (ImageInterpolation.Low) // 低度使用插值圖檔資料
           

可以看到,原圖放大後有馬賽克,而高插值的方式就很平滑了。效果對比如下:

HarmonyOS —— Image元件和ImageAnimator元件

. renderMode (ImageRenderMode): 設定圖檔渲染的模式。 相當于PS中對圖檔做去色處理,可将彩色圖檔變為灰階圖檔。

示例代碼:

/**
           * .renderMode(ImageRenderMode) 預設值Original,設定圖檔渲染的模式。
           *    ImageRenderMode.Original 按照原圖進行渲染,包括顔色。
           *    ImageRenderMode.Template 将圖像渲染為模闆圖像,忽略圖檔的顔色資訊。
           * 注意:SVG類型圖源不支援該屬性。
           */
          TextBody1({text:'.renderMode(ImageRenderMode) 設定圖檔渲染的模式'})
          Image("/common/images/banner.jpg")
            .width("100%")
            .aspectRatio(3.5)
            .renderMode(ImageRenderMode.Original) // 按照原圖進行渲染,包括顔色
          Image("/common/images/banner.jpg")
            .width("100%")
            .aspectRatio(3.5)
            .renderMode(ImageRenderMode.Template) // 忽略圖檔的顔色資訊
           

效果如下:

HarmonyOS —— Image元件和ImageAnimator元件

.sourceSize({width: number,height: number}): 設定圖檔解碼尺寸,将原始圖檔解碼成指定尺寸的圖檔,number類型機關為px。

一張原本尺寸為1200x750像素的圖檔,指定解碼尺寸為150x100像素的照片後,如果圖檔展示尺寸超過該尺寸,就會模糊,示例代碼如下:

/**
           * .sourceSize({width: number,height: number}) 設定圖檔解碼尺寸,将原始圖檔解碼成指定尺寸的圖檔,number類型機關為px。
           * 注意:PixelMap資源不支援該屬性。
           */
          TextBody1({text:'.sourceSize({width: number,height: number}) 設定圖檔解碼尺寸'})
          Image($r("app.media.cover"))
            .borderRadius($r("app.float.radius_L"))
            .sourceSize({
              width: 150,
              height: 100
            }) // 解碼為小尺寸後顯示模糊
          Image($r("app.media.cover")) // 原圖效果
            .borderRadius($r("app.float.radius_L"))
           

解碼為小尺寸和原圖的效果對比如下:

HarmonyOS —— Image元件和ImageAnimator元件

對于.sourceSize屬性的使用,我個人的看法是:如果原圖較小,通過sourceSize解碼為大尺寸,建議配合.interpolation (ImageInterpolation)屬性來設定圖檔的插值,改善畫質;如果原圖較大,通過sourceSize解碼為小尺寸,建議配合.objectFit(ImageFit.ScaleDown)屬性顯示為合适的尺寸,保證清晰度。

如有不同想法,歡迎留言讨論。

3.事件

1.onComplete(callback: (event?: { width: number, height: number, componentWidth: number, componentHeight: number, loadingStatus: number }) => void):圖檔成功加載時觸發該回調,傳回成功加載的圖源尺寸。

2.onError(callback: (event?: { componentWidth: number, componentHeight: number }) => void):圖檔加載出現異常時觸發該回調。

3.onFinish(callback: () => void) 當加載的源檔案為帶動效的svg圖檔時,當svg動效播放完成時會觸發這個回調,如果動效為無限循環動效,則不會觸發這個回調。

示例代碼:

/**
           * 事件:
           * 1.onComplete(callback: (event?: { width: number, height: number, componentWidth: number, componentHeight: number, loadingStatus: number }) => void):圖檔成功加載時觸發該回調,傳回成功加載的圖源尺寸。
           * 2.onError(callback: (event?: { componentWidth: number, componentHeight: number }) => void):圖檔加載出現異常時觸發該回調。
           * 3.onFinish(callback: () => void) 當加載的源檔案為帶動效的svg圖檔時,當svg動效播放完成時會觸發這個回調,如果動效為無限循環動效,則不會觸發這個回調。
           */
          H8({text:'3.事件'})
          Image("https://developer.huawei.com/images/new-content/Navigation/HW-LOGO.svg") // 使用網絡路徑的圖檔
            .width(300).height(65)
            .onComplete((msg: { width: number,height: number }) => {
              // 可根據 msg.width和 msg.height的大小決定卡片顯示風格等
            })
            .onError(() => {
              console.log('加載圖檔失敗')
            })
            .onFinish(() => {
              //
            })
           
4.圖像效果

前面示範了通過Image元件的.renderMode(ImageRenderMode)實作圖檔的去色效果。在基于TS擴充的聲明式開發範式中還有一些控制圖像效果的屬性,這些屬性不僅可以用于Image元件,也可以用于其它元件。

示例代碼如下:

/**
           * 圖像效果
           * 屬性:
           *  blur:number 為目前元件添加内容模糊效果,入參為模糊半徑,模糊半徑越大越模糊,為0時不模糊。
           *  backdropBlur:number 為目前元件添加背景模糊效果,入參為模糊半徑,模糊半徑越大越模糊,為0時不模糊。
           *  shadow:{radius: number,color?: Color,offsetX?: number,offsetY?: number}
           *    為目前元件添加陰影效果,入參為模糊半徑(必填)、陰影的顔色(可選,預設為灰色)、X軸的偏移量(可選,預設為0),Y軸的偏移量(可選,預設為0),偏移量機關為px。
           *  grayscale:number 預設值0.0,為目前元件添加灰階效果。值定義為灰階轉換的比例,入參1.0則完全轉為灰階圖像,入參則0.0圖像無變化,入參在0.0和1.0之間時,效果呈線性變化。(百分比)
           *  brightness:number 預設值1.0,為目前元件添加高光效果,入參為高光比例,值為1時沒有效果,小于1時亮度變暗,0為全黑;大于1時亮度增加,數值越大亮度越大。
           *  saturate:number 預設值1.0,為目前元件添加飽和度效果,飽和度為顔色中的含色成分和消色成分(灰)的比例,入參為1時,顯示原圖像,大于1時含色成分越大,飽和度越大;小于1時消色成分越大,飽和度越小。(百分比)
           *  contrast:number 預設值1.0,為目前元件添加對比度效果,入參為對比度的值,值為1時,顯示原圖;大于1時,值越大對比度越高,圖像越清晰醒目;小于1時,值越小對比度越低;當對比度為0時,圖像變為全灰。(百分比)
           *  invert:number 預設值0,反轉輸入的圖像。入參為圖像反轉的比例。值為1時完全反轉。值為0則圖像無變化。(百分比)
           *  sepia:number 預設值0,将圖像轉換為深褐色。入參為圖像反轉的比例。值為1則完全是深褐色的,值為0圖像無變化。 (百分比)
           *  hueRotate:number 預設值0deg,為目前元件添加色相旋轉效果,入參為旋轉的角度值。當入參為0deg時圖像無變化(預設值是0deg),入參沒有最大值,超過360deg的值相當于又繞一圈。
           */
          H8({text:'4.圖像效果'})
          TextBody1({text:'添加内容模糊效果'})
          Image("/common/images/banner.jpg") // /common/images目錄下的圖檔
            .width("100%")
            .aspectRatio(3.5)
            .blur(3) // 為目前元件添加内容模糊效果

          TextBody1({text:'背景模糊效果'})
          Row().width('100%').height(240)
            .backgroundImage('/common/images/banner.jpg')
            .backgroundImageSize({ width: 1200, height: 800 })
            .backgroundImagePosition(Alignment.Center)
            .backdropBlur(3)

          TextBody1({text:'添加陰影效果'})
          Image("/common/images/banner.jpg").width('100%').aspectRatio(3.5)
            .shadow({ radius: 10, color: Color.Gray, offsetX: 5, offsetY: 5 })

          TextBody1({text:'添加灰階效果'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .grayscale(0.6)

          TextBody1({text:'添加高光效果'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .brightness(2.0)

          TextBody1({text:'添加飽和度效果'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .saturate(2.0)

          TextBody1({text:'添加對比度效果'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .contrast(2.0)

          TextBody1({text:'反轉輸入的圖像'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .invert(1)

          TextBody1({text:'圖像轉換為深褐色'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .sepia(1)

          TextBody1({text:'色相旋轉效果'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .hueRotate(90)
           

上述代碼的效果可以通過遠端模拟器體驗:

HarmonyOS —— Image元件和ImageAnimator元件
5.共享元素轉場

在圖檔清單頁面給縮略圖設定一個id,在放大顯示圖檔的展示頁也給圖檔設定一個相同的id, 利用共享元素轉場,将目前頁面的圖檔轉場到詳情頁面。

屬性:

. sharedTransition(id: string, options?: Object) : 兩個頁面的元件配置為同一個id,則轉場過程中會進行共享元素轉場,配置為空字元串時不會有共享元素轉場效果。 其中options參數說明如下:

duration: number 機關為毫秒,預設動畫時長為1000毫秒。

curve : Curve | Curves 預設曲線為線性

delay:number 預設值0,機關為毫秒,預設不延時播放。

示例代碼:

首先在ImageSample.ets頁面添加如下代碼:

/**
           * 5.共享元素轉場
           * 共享元素轉場支援頁面間的轉場,如目前頁面的圖檔轉場至下一頁面中。
           *
           * 屬性:
           *  .sharedTransition(id: string,options?: Object)
           *  兩個頁面的元件配置為同一個id,則轉場過程中會進行共享元素轉場,配置為空字元串時不會有共享元素轉場效果。
           *    options參數說明:
           *    duration:number 預設值1000,機關為毫秒,預設動畫時長為1000毫秒。
           *    curve:Curve | Curves 預設值Linear,預設曲線為線性
           *      Curve.Linear 表示動畫從頭到尾的速度都是相同的。
           *      Curve.Ease 表示動畫以低速開始,然後加快,在結束前變慢,CubicBezier(0.25, 0.1, 0.25, 1.0)。
           *      Curve.EaseIn 表示動畫以低速開始,CubicBezier(0.42, 0.0, 1.0, 1.0)。
           *      Curve.EaseOut 表示動畫以低速結束,CubicBezier(0.0, 0.0, 0.58, 1.0)。
           *      Curve.EaseInOut 表示動畫以低速開始和結束,CubicBezier(0.42, 0.0, 0.58, 1.0)。
           *      Curve.FastOutSlowIn 标準曲線,cubic-bezier(0.4, 0.0, 0.2, 1.0)。
           *      Curve.LinearOutSlowIn 減速曲線,cubic-bezier(0.0, 0.0, 0.2, 1.0)。
           *      Curve.FastOutLinearIn 加速曲線,cubic-bezier(0.4, 0.0, 1.0, 1.0)。
           *      Curve.ExtremeDeceleration 急緩曲線,cubic-bezier(0.0, 0.0, 0.0, 1.0)。
           *      Curve.Sharp 銳利曲線,cubic-bezier(0.33, 0.0, 0.67, 1.0)。
           *      Curve.Rhythm 節奏曲線,cubic-bezier(0.7, 0.0, 0.2, 1.0)。
           *      Curve.Smooth 平滑曲線,cubic-bezier(0.4, 0.0, 0.4, 1.0)。
           *      Curve.Friction 阻尼曲線,CubicBezier(0.2, 0.0, 0.2, 1.0)。
           *    delay:number 預設值0,機關為毫秒,預設不延時播放。
           */
          H8({text:'5.共享元素轉場'})
          Navigator({ target: 'pages/ImageDetailSample', type: NavigationType.Push }) {
            Image($r("app.media.cover"))
              .width(100)
              .aspectRatio(1.5)
              .sharedTransition('sharedId1', { duration: 800, curve: Curve.Linear, delay: 100 })
          }
           

然後建立一個ImageDetailSample.ets頁面,代碼如下:

@Entry
@Component
struct ImageDetailSample {
  build() {
    Column({space:8}) {
      Navigator({ target: 'pages/ImageSample', type: NavigationType.Back }) {
        Image($r("app.media.cover"))
          .width("100%")
          .aspectRatio(1.5)
          .borderRadius($r("app.float.radius_L"))
          .sharedTransition('sharedId1') // 設定和上級頁面相同的id
      }
    }
    .width('100%')
    .height('100%')
    .padding({top: $r("app.float.spaceTop"), bottom:$r("app.float.spaceBottom"), left:$r("app.float.spaceLeft"), right: $r("app.float.spaceRight")})
    .backgroundColor($r("app.color.appBg"))
  }
}
           

建議在DevEco Studioi中通過本地預覽器或遠端模拟器體驗流暢的轉場動畫效果,可以點選放大,也可以點選傳回上級頁面時縮小,運作效果如下:

HarmonyOS —— Image元件和ImageAnimator元件

3.3.3 ImageAnimator元件

在ArkUI eTS語言中,可通過Image元件展示gif動畫,同時,提供了一個ImageAnimator元件,提供幀動畫元件來實作逐幀播放圖檔的能力,可以配置需要播放的圖檔清單,每張圖檔可以配置時長。

建立ImageAnimatorSample.ets頁面,初始化代碼如下:

import {H8} from './index'

/**
 * 3.3.3 ImageAnimator元件
 */
@Entry
@Component
struct ImageDetailSample {
  build() {
    Column({space:8}) {
      // 傳回首頁
      Row({space:8}){
        Image($r("app.media.ic_back")).width(24).height(24)

        Navigator({ target: 'pages/index', type: NavigationType.Back }) {
          H8({text:'傳回'})
        }
      }

      // TODO
    }
    .width('100%')
    .height('100%')
    .padding({top: $r("app.float.spaceTop"), bottom:$r("app.float.spaceBottom"), left:$r("app.float.spaceLeft"), right: $r("app.float.spaceRight")})
    .backgroundColor($r("app.color.appBg"))
    .alignItems(HorizontalAlign.Start)
  }
}
           
1.接口

ImageAnimator()

2.屬性

.images(Array<{

src:string, //圖檔路徑,圖檔格式為svg,png和jpg。

width?:Length, //圖檔寬度。

height?:Length, //圖檔高度。

top?:Length, //圖檔相對于元件左上角的縱向坐标。

left?:Length, //圖檔相對于元件左上角的橫向坐标。

duration?:number //每一幀圖檔的播放時長,機關毫秒。

}>):設定圖檔幀資訊集合。

.state(AnimationStatus):用于控制播放狀态。

.duration(number):持續時間

.reverse(boolean):設定播放順序。

.fixedSize(boolean):設定圖檔大小是否固定為元件大小。

.preDecode(number):是否啟用預解碼。

.fillMode(FillMode): 設定動畫開始前和結束後的狀态 。

.iterations(number): 預設播放一次,設定為-1時表示無限次播放。

3.事件

onStart() => void : 狀态回調,動畫開始播放時觸發。

onPause() => void : 狀态回調,動畫暫停播放時觸發。

onRepeat() => void : 狀态回調,動畫重新播放時觸發。

onCancel() => void : 狀态回調,動畫取消播放時觸發。

onFinish() => void : 狀态回調,動畫播放完成時觸發。

示例代碼如下:

首先,在代碼"build(){"之前加入如下代碼:

@State state: AnimationStatus = AnimationStatus.Initial
  @State reverse: boolean = false
  @State iterations: number = 1
           

代碼位置如下圖所示:

HarmonyOS —— Image元件和ImageAnimator元件

然後在"// TODO"處加入如下代碼:

/**
       * 1.接口:ImageAnimator()
       * 2.屬性:
       *  images:Array<{
            src:string, //圖檔路徑,圖檔格式為svg,png和jpg。
            width?:Length, //圖檔寬度。
            height?:Length, //圖檔高度。
            top?:Length, //圖檔相對于元件左上角的縱向坐标。
            left?:Length, //圖檔相對于元件左上角的橫向坐标。
            duration?:number //每一幀圖檔的播放時長,機關毫秒。
          }> 設定圖檔幀資訊集合。每一幀的幀資訊包含圖檔路徑、圖檔大小、圖檔位置和圖檔播放時長資訊。
       *  state:AnimationStatus 預設值Initial,預設為初始狀态,用于控制播放狀态。
       *    AnimationStatus.Initial 動畫初始狀态。
       *    AnimationStatus.Running 動畫處于播放狀态。
       *    AnimationStatus.Paused 動畫處于暫停狀态。
       *    AnimationStatus.Stopped 動畫處于停止狀态。
       *  duration:number 預設值1000,機關為毫秒,預設時長為1000ms;duration為0時,不播放圖檔;值的改變隻會在下一次循環開始時生效;當images中設定了單獨的duration後,該屬性設定無效。
       *  reverse:boolean 預設值false,設定播放順序。false表示從第1張圖檔播放到最後1張圖檔; true表示從最後1張圖檔播放到第1張圖檔。
       *  fixedSize:boolean 預設值true,設定圖檔大小是否固定為元件大小。 true表示圖檔大小與元件大小一緻,此時設定圖檔的width 、height 、top 和left屬性是無效的。false表示每一張圖檔的 width 、height 、top和left屬性都要單獨設定。
       *  preDecode:number 預設值0,是否啟用預解碼,預設值為0,即不啟用預解碼,如該值設為2,則播放目前頁時會提前加載後面兩張圖檔至緩存以提升性能。
       *  fillMode:FillMode 預設值Forwards,設定動畫開始前和結束後的狀态,可選值參見FillMode說明。
       *    FillMode.None 播放完成後恢複初始狀态。
       *    FillMode.Forwards 播放完成後保持動畫結束時的狀态。
       *    FillMode.Backwards 在animation-delay所指定的一段時間内,在動畫顯示之前,應用開始屬性值。
       *    FillMode.Both 向前和向後填充模式都被應用。
       *  iterations:number 預設值1,預設播放一次,設定為-1時表示無限次播放。
       *
       * 3.事件:
       *  onStart() => void 狀态回調,動畫開始播放時觸發。
       *  onPause() => void 狀态回調,動畫暫停播放時觸發。
       *  onRepeat() => void 狀态回調,動畫重新播放時觸發。
       *  onCancel() => void 狀态回調,動畫取消播放時觸發。
       *  onFinish() => void 狀态回調,動畫播放完成時觸發。
       */
      ImageAnimator()
        .images([
          {
            src: '/common/images/01.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/02.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/03.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/04.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/05.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/06.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/07.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/08.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/09.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/10.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/11.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/12.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          }
        ]) // 設定圖檔幀資訊集合
        .state(this.state) // 用于控制播放狀态
        .reverse(this.reverse) // 設定播放順序,
        .fixedSize(false) // 設定圖檔大小是否固定為元件大小
        .preDecode(2) // 是否啟用預解碼
        .fillMode(FillMode.None) // 設定動畫開始前和結束後的狀态
        .iterations(this.iterations) // 預設播放一次,設定為-1時表示無限次播放
        .width(300).height(300)
        .margin({top:100})
        .onStart(() => { // 狀态回調,動畫開始播放時觸發
          console.info('動畫開始播放')
        })
        .onPause(() => { // 狀态回調,動畫暫停播放時觸發
          console.info('動畫暫停播放')
        })
        .onRepeat(() => { // 狀态回調,動畫重新播放時觸發
          console.info('動畫重新播放')
        })
        .onCancel(() => { // 狀态回調,動畫取消播放時觸發
          console.info('動畫取消播放')
        })
        .onFinish(() => { // 狀态回調,動畫播放完成時觸發
          console.info('動畫播放完成')
        })
      Row() {
        Button('開始').width(100).padding(5).onClick(() => {
          this.state = AnimationStatus.Running
        })
        Button('暫停').width(100).padding(5).onClick(() => {
          this.state = AnimationStatus.Paused
        })
        Button('停止').width(100).padding(5).onClick(() => {
          this.state = AnimationStatus.Stopped
        })
      }
      Row() {
        Button('反向播放').width(100).padding(5).onClick(() => {
          this.reverse = !this.reverse
        })
        Button('播放一次').width(100).padding(5).onClick(() => {
          this.iterations = 1
        })
        Button('無限循環').width(100).padding(5).onClick(() => {
          this.iterations = -1
        })
      }
           

運作效果如下:

HarmonyOS —— Image元件和ImageAnimator元件

【本節源碼:https://gitee.com/cloudev/harmonyos3/tree/master/3.0/BaseComponent 】

繼續閱讀