動(dòng)畫(huà)的原理是在一個(gè)時(shí)間段內(nèi),多次改變UI外觀,由于人眼會(huì)產(chǎn)生視覺(jué)暫留,所以最終看到的就是一個(gè)“連續(xù)”的動(dòng)畫(huà)。UI的一次改變稱(chēng)為一個(gè)動(dòng)畫(huà)幀,對(duì)應(yīng)一次屏幕刷新,而決定動(dòng)畫(huà)流暢度的一個(gè)重要指標(biāo)就是幀率FPS(Frame Per Second),即每秒的動(dòng)畫(huà)幀數(shù),幀率越高則動(dòng)畫(huà)就會(huì)越流暢。
ArkUI中,產(chǎn)生動(dòng)畫(huà)的方式是改變屬性值且指定動(dòng)畫(huà)參數(shù)。動(dòng)畫(huà)參數(shù)包含了如動(dòng)畫(huà)時(shí)長(zhǎng)、變化規(guī)律(即曲線(xiàn))等參數(shù)。當(dāng)屬性值發(fā)生變化后,按照動(dòng)畫(huà)參數(shù),從原來(lái)的狀態(tài)過(guò)渡到新的狀態(tài),即形成一個(gè)動(dòng)畫(huà)。
ArkUI提供的動(dòng)畫(huà)能力按照頁(yè)面的分類(lèi)方式,可分為頁(yè)面內(nèi)的動(dòng)畫(huà)和頁(yè)面間的動(dòng)畫(huà)。如下圖所示,頁(yè)面內(nèi)的動(dòng)畫(huà)指在一個(gè)頁(yè)面內(nèi)即可發(fā)生的動(dòng)畫(huà),頁(yè)面間的動(dòng)畫(huà)指兩個(gè)頁(yè)面跳轉(zhuǎn)時(shí)才會(huì)發(fā)生的動(dòng)畫(huà)。

圖1 按照頁(yè)面分類(lèi)的動(dòng)畫(huà)

如果按照基礎(chǔ)能力分,可分為屬性動(dòng)畫(huà)、顯式動(dòng)畫(huà)、轉(zhuǎn)場(chǎng)動(dòng)畫(huà)三部分。如下圖所示。

圖2 按照基礎(chǔ)能力分類(lèi)的動(dòng)畫(huà)

使用顯式動(dòng)畫(huà)產(chǎn)生布局更新動(dòng)畫(huà)
顯式動(dòng)畫(huà)的接口為:
animateTo(value: AnimateParam, event: () => void): void
第一個(gè)參數(shù)指定動(dòng)畫(huà)參數(shù),第二個(gè)參數(shù)為動(dòng)畫(huà)的閉包函數(shù)。
以下是使用顯式動(dòng)畫(huà)產(chǎn)生布局更新動(dòng)畫(huà)的示例。示例中,當(dāng)Column組件的alignItems屬性改變后,其子組件的布局位置結(jié)果發(fā)生變化。只要該屬性是在animateTo的閉包函數(shù)中修改的,那么由其引起的所有變化都會(huì)按照animateTo的動(dòng)畫(huà)參數(shù)執(zhí)行動(dòng)畫(huà)過(guò)渡到終點(diǎn)值。
@Entry
@Component
struct LayoutChange {
// 用于控制Column的alignItems屬性
@State itemAlign: HorizontalAlign = HorizontalAlign.Start;
allAlign: HorizontalAlign[] = [HorizontalAlign.Start, HorizontalAlign.Center, HorizontalAlign.End];
alignIndex: number = 0;
build() {
Column() {
Column({ space: 10 }) {
Button("1").width(100).height(50)
Button("2").width(100).height(50)
Button("3").width(100).height(50)
}
.margin(20)
.alignItems(this.itemAlign)
.borderWidth(2)
.width("90%")
.height(200)
Button("click").onClick(() => {
// 動(dòng)畫(huà)時(shí)長(zhǎng)為1000ms,曲線(xiàn)為EaseInOut
animateTo({ duration: 1000, curve: Curve.EaseInOut }, () => {
this.alignIndex = (this.alignIndex + 1) % this.allAlign.length;
// 在閉包函數(shù)中修改this.itemAlign參數(shù),使Column容器內(nèi)部孩子的布局方式變化,使用動(dòng)畫(huà)過(guò)渡到新位置
this.itemAlign = this.allAlign[this.alignIndex];
});
})
}
.width("100%")
.height("100%")
}
}
除直接改變布局方式外,也可直接修改組件的寬、高、位置。
@Entry
@Component
struct LayoutChange2 {
@State myWidth: number = 100;
@State myHeight: number = 50;
// 標(biāo)志位,true和false分別對(duì)應(yīng)一組myWidth、myHeight值
@State flag: boolean = false;
build() {
Column({ space: 10 }) {
Button("text")
.type(ButtonType.Normal)
.width(this.myWidth)
.height(this.myHeight)
.margin(20)
Button("area: click me")
.fontSize(12)
.margin(20)
.onClick(() => {
animateTo({ duration: 1000, curve: Curve.Ease }, () => {
// 動(dòng)畫(huà)閉包中根據(jù)標(biāo)志位改變控制第一個(gè)Button寬高的狀態(tài)變量,使第一個(gè)Button做寬高動(dòng)畫(huà)
if (this.flag) {
this.myWidth = 100;
this.myHeight = 50;
} else {
this.myWidth = 200;
this.myHeight = 100;
}
this.flag = !this.flag;
});
})
}
.width("100%")
.height("100%")
}
}
另一種方式是給第二個(gè)Button添加布局約束,如position的位置約束,使其位置不被第一個(gè)Button的寬高影響。核心代碼如下:
Column({ space: 10 }) {
Button("text")
.type(ButtonType.Normal)
.width(this.myWidth)
.height(this.myHeight)
.margin(20)
Button("area: click me")
.fontSize(12)
// 配置position屬性固定,使自己的布局位置不被第一個(gè)Button的寬高影響
.position({ x: "30%", y: 200 })
.onClick(() => {
animateTo({ duration: 1000, curve: Curve.Ease }, () => {
// 動(dòng)畫(huà)閉包中根據(jù)標(biāo)志位改變控制第一個(gè)Button寬高的狀態(tài)變量,使第一個(gè)Button做寬高動(dòng)畫(huà)
if (this.flag) {
this.myWidth = 100;
this.myHeight = 50;
} else {
this.myWidth = 200;
this.myHeight = 100;
}
this.flag = !this.flag;
});
})
}
.width("100%")
.height("100%")
使用屬性動(dòng)畫(huà)產(chǎn)生布局更新動(dòng)畫(huà)
顯式動(dòng)畫(huà)把要執(zhí)行動(dòng)畫(huà)的屬性的修改放在閉包函數(shù)中觸發(fā)動(dòng)畫(huà),而屬性動(dòng)畫(huà)則無(wú)需使用閉包,把a(bǔ)nimation屬性加在要做屬性動(dòng)畫(huà)的組件的屬性后即可。
屬性動(dòng)畫(huà)的接口為:
animation(value: AnimateParam)
其入?yún)閯?dòng)畫(huà)參數(shù)。想要組件隨某個(gè)屬性值的變化而產(chǎn)生動(dòng)畫(huà),此屬性需要加在animation屬性之前。有的屬性變化不希望通過(guò)animation產(chǎn)生屬性動(dòng)畫(huà),可以放在animation之后。上面顯式動(dòng)畫(huà)的示例很容易改為用屬性動(dòng)畫(huà)實(shí)現(xiàn)。例如:
@Entry
@Component
struct LayoutChange2 {
@State myWidth: number = 100;
@State myHeight: number = 50;
@State flag: boolean = false;
@State myColor: Color = Color.Blue;
build() {
Column({ space: 10 }) {
Button("text")
.type(ButtonType.Normal)
.width(this.myWidth)
.height(this.myHeight)
// animation只對(duì)其上面的type、width、height屬性生效,時(shí)長(zhǎng)為1000ms,曲線(xiàn)為Ease
.animation({ duration: 1000, curve: Curve.Ease })
// animation對(duì)下面的backgroundColor、margin屬性不生效
.backgroundColor(this.myColor)
.margin(20)
Button("area: click me")
.fontSize(12)
.onClick(() => {
// 改變屬性值,配置了屬性動(dòng)畫(huà)的屬性會(huì)進(jìn)行動(dòng)畫(huà)過(guò)渡
if (this.flag) {
this.myWidth = 100;
this.myHeight = 50;
this.myColor = Color.Blue;
} else {
this.myWidth = 200;
this.myHeight = 100;
this.myColor = Color.Pink;
}
this.flag = !this.flag;
})
}
}
}
上述示例中,第一個(gè)button上的animation屬性,只對(duì)寫(xiě)在animation之前的type、width、height屬性生效,而對(duì)寫(xiě)在animation之后的backgroundColor、margin屬性無(wú)效。運(yùn)行結(jié)果是width、height屬性會(huì)按照animation的動(dòng)畫(huà)參數(shù)執(zhí)行動(dòng)畫(huà),而backgroundColor會(huì)直接跳變,不會(huì)產(chǎn)生動(dòng)畫(huà)
審核編輯 黃宇
-
鴻蒙
+關(guān)注
關(guān)注
60文章
2963瀏覽量
45899
發(fā)布評(píng)論請(qǐng)先 登錄
想體驗(yàn)鴻蒙生態(tài),該怎么獲取鴻蒙開(kāi)發(fā)板?有哪些途徑?
如何申請(qǐng)鴻蒙開(kāi)發(fā)板?想體驗(yàn)鴻蒙生態(tài)。
【M-K1HSE開(kāi)發(fā)板免費(fèi)體驗(yàn)】相關(guān)源碼之閱讀和分析1-使用XComponent + Vsync 實(shí)現(xiàn)自定義動(dòng)畫(huà)
【HarmonyOS 5】金融應(yīng)用開(kāi)發(fā)鴻蒙組件實(shí)踐
鴻蒙5開(kāi)發(fā)寶藏案例分享---一多開(kāi)發(fā)實(shí)例(音樂(lè))
鴻蒙5開(kāi)發(fā)寶藏案例分享---優(yōu)化應(yīng)用時(shí)延問(wèn)題
鴻蒙5開(kāi)發(fā)寶藏案例分享---Web頁(yè)面內(nèi)點(diǎn)擊響應(yīng)時(shí)延分析
鴻蒙5開(kāi)發(fā)寶藏案例分享---分析幀率問(wèn)題
鴻蒙5開(kāi)發(fā)寶藏案例分享---點(diǎn)擊完成時(shí)延分析
鴻蒙5開(kāi)發(fā)寶藏案例分享---性能體驗(yàn)設(shè)計(jì)
鴻蒙5開(kāi)發(fā)寶藏案例分享---體驗(yàn)流暢的首頁(yè)信息流
2025開(kāi)源鴻蒙開(kāi)發(fā)者大會(huì)圓滿(mǎn)落幕
DevEco Studio AI輔助開(kāi)發(fā)工具兩大升級(jí)功能 鴻蒙應(yīng)用開(kāi)發(fā)效率再提升
DialogHub上線(xiàn)OpenHarmony開(kāi)源社區(qū),高效開(kāi)發(fā)鴻蒙應(yīng)用彈窗
鴻蒙北向開(kāi)發(fā)OpenHarmony5.0 DevEco Studio開(kāi)發(fā)工具安裝與配置
鴻蒙開(kāi)發(fā)之發(fā)動(dòng)畫(huà)篇
評(píng)論