本節首先解決@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)
在手機淺色模式和平闆深色模式下效果如下:
使用網絡路徑
如果圖檔來源于網絡,接口還是和上面一樣,但是需要在config.json檔案中“js”節點的後面加入如下配置:
"reqPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
如下圖所示:
然後在ImageSample.ets頁面加入如下代碼:
TextBody1({text:'svg格式圖檔,使用網絡路徑'})
Image("https://developer.huawei.com/images/new-content/Navigation/HW-LOGO.svg") // 使用網絡路徑的圖檔
.width(300).height(65) // Logo指定寬高,不進行自适應縮放
效果如下:
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圖檔,淺色模式和深色模式下效果如下:
. 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)
在手機和平闆上,圖檔表現如下:
. 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) // 不重複繪制圖檔
運作效果:
. 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) // 低度使用插值圖檔資料
可以看到,原圖放大後有馬賽克,而高插值的方式就很平滑了。效果對比如下:
. 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) // 忽略圖檔的顔色資訊
效果如下:
.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"))
解碼為小尺寸和原圖的效果對比如下:
對于.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)
上述代碼的效果可以通過遠端模拟器體驗:
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中通過本地預覽器或遠端模拟器體驗流暢的轉場動畫效果,可以點選放大,也可以點選傳回上級頁面時縮小,運作效果如下:
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
代碼位置如下圖所示:
然後在"// 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
})
}
運作效果如下:
【本節源碼:https://gitee.com/cloudev/harmonyos3/tree/master/3.0/BaseComponent 】