布局更新動(dòng)畫

2024-02-07 12:41 更新

顯式動(dòng)畫(animateTo)和屬性動(dòng)畫(animation)是ArkUI提供的最基礎(chǔ)和常用的動(dòng)畫功能。在布局屬性(如尺寸屬性、位置屬性)發(fā)生變化時(shí),可以通過屬性動(dòng)畫或顯式動(dòng)畫,按照動(dòng)畫參數(shù)過渡到新的布局參數(shù)狀態(tài)。

動(dòng)畫類型

特點(diǎn)

顯式動(dòng)畫

閉包內(nèi)的變化均會(huì)觸發(fā)動(dòng)畫,包括由數(shù)據(jù)變化引起的組件的增刪、組件屬性的變化等,可以做較為復(fù)雜的動(dòng)畫。

屬性動(dòng)畫

動(dòng)畫設(shè)置簡單,屬性變化時(shí)自動(dòng)觸發(fā)動(dòng)畫。

使用顯式動(dòng)畫產(chǎn)生布局更新動(dòng)畫

顯式動(dòng)畫的接口為:

  1. animateTo(value: AnimateParam, event: () => void): void

第一個(gè)參數(shù)指定動(dòng)畫參數(shù),第二個(gè)參數(shù)為動(dòng)畫的閉包函數(shù)。

以下是使用顯式動(dòng)畫產(chǎn)生布局更新動(dòng)畫的示例。示例中,當(dāng)Column組件的alignItems屬性改變后,其子組件的布局位置結(jié)果發(fā)生變化。只要該屬性是在animateTo的閉包函數(shù)中修改的,那么由其引起的所有變化都會(huì)按照animateTo的動(dòng)畫參數(shù)執(zhí)行動(dòng)畫過渡到終點(diǎn)值。

  1. @Entry
  2. @Component
  3. struct LayoutChange {
  4. // 用于控制Column的alignItems屬性
  5. @State itemAlign: HorizontalAlign = HorizontalAlign.Start;
  6. allAlign: HorizontalAlign[] = [HorizontalAlign.Start, HorizontalAlign.Center, HorizontalAlign.End];
  7. alignIndex: number = 0;
  8. build() {
  9. Column() {
  10. Column({ space: 10 }) {
  11. Button("1").width(100).height(50)
  12. Button("2").width(100).height(50)
  13. Button("3").width(100).height(50)
  14. }
  15. .margin(20)
  16. .alignItems(this.itemAlign)
  17. .borderWidth(2)
  18. .width("90%")
  19. .height(200)
  20. Button("click").onClick(() => {
  21. // 動(dòng)畫時(shí)長為1000ms,曲線為EaseInOut
  22. animateTo({ duration: 1000, curve: Curve.EaseInOut }, () => {
  23. this.alignIndex = (this.alignIndex + 1) % this.allAlign.length;
  24. // 在閉包函數(shù)中修改this.itemAlign參數(shù),使Column容器內(nèi)部孩子的布局方式變化,使用動(dòng)畫過渡到新位置
  25. this.itemAlign = this.allAlign[this.alignIndex];
  26. });
  27. })
  28. }
  29. .width("100%")
  30. .height("100%")
  31. }
  32. }

除直接改變布局方式外,也可直接修改組件的寬、高、位置。

  1. @Entry
  2. @Component
  3. struct LayoutChange2 {
  4. @State myWidth: number = 100;
  5. @State myHeight: number = 50;
  6. // 標(biāo)志位,true和false分別對(duì)應(yīng)一組myWidth、myHeight值
  7. @State flag: boolean = false;
  8. build() {
  9. Column({ space: 10 }) {
  10. Button("text")
  11. .type(ButtonType.Normal)
  12. .width(this.myWidth)
  13. .height(this.myHeight)
  14. .margin(20)
  15. Button("area: click me")
  16. .fontSize(12)
  17. .margin(20)
  18. .onClick(() => {
  19. animateTo({ duration: 1000, curve: Curve.Ease }, () => {
  20. // 動(dòng)畫閉包中根據(jù)標(biāo)志位改變控制第一個(gè)Button寬高的狀態(tài)變量,使第一個(gè)Button做寬高動(dòng)畫
  21. if (this.flag) {
  22. this.myWidth = 100;
  23. this.myHeight = 50;
  24. } else {
  25. this.myWidth = 200;
  26. this.myHeight = 100;
  27. }
  28. this.flag = !this.flag;
  29. });
  30. })
  31. }
  32. .width("100%")
  33. .height("100%")
  34. }
  35. }

在第二個(gè)Button的點(diǎn)擊事件中,使用animateTo函數(shù),在閉包中修改this.myWidth和this.myHeight狀態(tài)變量,而這兩個(gè)狀態(tài)變量分別為第一個(gè)Button的寬、高屬性值,所以第一個(gè)Button做了寬高動(dòng)畫。效果如下圖。

與此同時(shí),第二個(gè)Button也產(chǎn)生了一個(gè)位置動(dòng)畫。這是由于第一個(gè)Button的寬高變化后,引起了Column內(nèi)部其他組件的布局結(jié)果也發(fā)生了變化,第二個(gè)Button的布局發(fā)生變化也是由于閉包內(nèi)改變第一個(gè)Button的寬高造成的。

如果不希望第二個(gè)Button有動(dòng)畫效果,有兩種方式可以實(shí)現(xiàn)。一種是給做第一個(gè)Button外面再加一個(gè)容器,使其動(dòng)畫前后的大小都在容器的范圍內(nèi),這樣第二個(gè)Button的位置不會(huì)被第一個(gè)Button的位置所影響。修改后的核心代碼如下。

  1. Column({ space: 10 }) {
  2. Column() {
  3. // Button放在足夠大的容器內(nèi),使其不影響更外層的組件位置
  4. Button("text")
  5. .type(ButtonType.Normal)
  6. .width(this.myWidth)
  7. .height(this.myHeight)
  8. }
  9. .margin(20)
  10. .width(200)
  11. .height(100)
  12. Button("area: click me")
  13. .fontSize(12)
  14. .onClick(() => {
  15. animateTo({ duration: 1000, curve: Curve.Ease }, () => {
  16. // 動(dòng)畫閉包中根據(jù)標(biāo)志位改變控制第一個(gè)Button寬高的狀態(tài)變量,使第一個(gè)Button做寬高動(dòng)畫
  17. if (this.flag) {
  18. this.myWidth = 100;
  19. this.myHeight = 50;
  20. } else {
  21. this.myWidth = 200;
  22. this.myHeight = 100;
  23. }
  24. this.flag = !this.flag;
  25. });
  26. })
  27. }
  28. .width("100%")
  29. .height("100%")

另一種方式是給第二個(gè)Button添加布局約束,如position的位置約束,使其位置不被第一個(gè)Button的寬高影響。核心代碼如下:

  1. Column({ space: 10 }) {
  2. Button("text")
  3. .type(ButtonType.Normal)
  4. .width(this.myWidth)
  5. .height(this.myHeight)
  6. .margin(20)
  7. Button("area: click me")
  8. .fontSize(12)
  9. // 配置position屬性固定,使自己的布局位置不被第一個(gè)Button的寬高影響
  10. .position({ x: "30%", y: 200 })
  11. .onClick(() => {
  12. animateTo({ duration: 1000, curve: Curve.Ease }, () => {
  13. // 動(dòng)畫閉包中根據(jù)標(biāo)志位改變控制第一個(gè)Button寬高的狀態(tài)變量,使第一個(gè)Button做寬高動(dòng)畫
  14. if (this.flag) {
  15. this.myWidth = 100;
  16. this.myHeight = 50;
  17. } else {
  18. this.myWidth = 200;
  19. this.myHeight = 100;
  20. }
  21. this.flag = !this.flag;
  22. });
  23. })
  24. }
  25. .width("100%")
  26. .height("100%")

使用屬性動(dòng)畫產(chǎn)生布局更新動(dòng)畫

顯式動(dòng)畫把要執(zhí)行動(dòng)畫的屬性的修改放在閉包函數(shù)中觸發(fā)動(dòng)畫,而屬性動(dòng)畫則無需使用閉包,把a(bǔ)nimation屬性加在要做屬性動(dòng)畫的組件的屬性后即可。

屬性動(dòng)畫的接口為:

  1. animation(value: AnimateParam)

其入?yún)閯?dòng)畫參數(shù)。想要組件隨某個(gè)屬性值的變化而產(chǎn)生動(dòng)畫,此屬性需要加在animation屬性之前。有的屬性變化不希望通過animation產(chǎn)生屬性動(dòng)畫,可以放在animation之后。上面顯式動(dòng)畫的示例很容易改為用屬性動(dòng)畫實(shí)現(xiàn)。例如:

  1. @Entry
  2. @Component
  3. struct LayoutChange2 {
  4. @State myWidth: number = 100;
  5. @State myHeight: number = 50;
  6. @State flag: boolean = false;
  7. @State myColor: Color = Color.Blue;
  8. build() {
  9. Column({ space: 10 }) {
  10. Button("text")
  11. .type(ButtonType.Normal)
  12. .width(this.myWidth)
  13. .height(this.myHeight)
  14. // animation只對(duì)其上面的type、width、height屬性生效,時(shí)長為1000ms,曲線為Ease
  15. .animation({ duration: 1000, curve: Curve.Ease })
  16. // animation對(duì)下面的backgroundColor、margin屬性不生效
  17. .backgroundColor(this.myColor)
  18. .margin(20)
  19. Button("area: click me")
  20. .fontSize(12)
  21. .onClick(() => {
  22. // 改變屬性值,配置了屬性動(dòng)畫的屬性會(huì)進(jìn)行動(dòng)畫過渡
  23. if (this.flag) {
  24. this.myWidth = 100;
  25. this.myHeight = 50;
  26. this.myColor = Color.Blue;
  27. } else {
  28. this.myWidth = 200;
  29. this.myHeight = 100;
  30. this.myColor = Color.Pink;
  31. }
  32. this.flag = !this.flag;
  33. })
  34. }
  35. }
  36. }

上述示例中,第一個(gè)button上的animation屬性,只對(duì)寫在animation之前的type、width、height屬性生效,而對(duì)寫在animation之后的backgroundColor、margin屬性無效。運(yùn)行結(jié)果是width、height屬性會(huì)按照animation的動(dòng)畫參數(shù)執(zhí)行動(dòng)畫,而backgroundColor會(huì)直接跳變,不會(huì)產(chǎn)生動(dòng)畫。效果如下圖:

說明

1. 使用屬性動(dòng)畫時(shí),會(huì)按照指定的屬性動(dòng)畫參數(shù)執(zhí)行動(dòng)畫。每個(gè)組件可為自己的屬性配置不同參數(shù)的屬性動(dòng)畫。

2. 顯式動(dòng)畫會(huì)對(duì)動(dòng)畫閉包前后造成的所有界面差異執(zhí)行動(dòng)畫,且使用同一動(dòng)畫參數(shù),適用于統(tǒng)一執(zhí)行的場景。此外,顯式動(dòng)畫也可以用于一些非屬性變量造成的動(dòng)畫,如if/else的條件,F(xiàn)orEach使用的數(shù)組元素的刪減。

3. 如果一個(gè)屬性配置了屬性動(dòng)畫,且在顯式動(dòng)畫閉包中改變該屬性值,屬性動(dòng)畫優(yōu)先生效,會(huì)使用屬性動(dòng)畫的動(dòng)畫參數(shù)。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)