鴻蒙HarmonyOS實戰-ArkUI動畫(彈簧曲線動畫)

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

🚀前言

彈簧曲線動畫是一種模擬彈簧運動的動畫效果,透過改變彈簧的拉伸或壓縮來表現不同的運動狀態。以下是製作彈簧曲線動畫的步驟:

  1. 建立一個彈簧的模型,可以使用圓形或者曲線來代表彈簧的形狀。
  2. 將彈簧固定在一個點上,這個點可以是螢幕中心或其他位置。
  3. 定義一個目標位置,彈簧將會朝向這個位置進行拉伸或壓縮。
  4. 使用動畫技術,逐步改變彈簧的形狀,使其逐漸接近目標位置。
  5. 在動畫過程中,可以考慮新增一些物理效果,如慣性、摩擦力等,以增加動畫的真實感。
  6. 迴圈播放動畫,以實現不斷的彈簧運動效果。

透過調整彈簧的屬性和動畫引數,可以製作出不同型別的彈簧曲線動畫,如擺動、震動、彈跳等效果。可以使用程式語言或動畫軟體來實現彈簧曲線動畫。

🚀一、彈簧曲線動畫

ArkUI提供了預置動畫曲線,用於指定動畫屬性從起始值到終止值的變化規律,例如Linear、Ease、EaseIn等。此外,ArkUI還提供了由彈簧振子物理模型產生的彈簧曲線。透過使用彈簧曲線,開發者可以實現超過設定終止值的震盪效果,直至最終停止。彈簧曲線具有更強的互動性和可玩性,與其他曲線相比具有更強的動畫效果。

彈簧曲線的介面包括兩類,即springCurve和springMotion以及responsiveSpringMotion。這兩種方式都可以生成彈簧曲線。

🔎1.使用springCurve

springCurve的介面為:

springCurve(velocity: number, mass: number, stiffness: number, damping: number)
  • velocity:初速度是指物體在某一瞬間的速度,通常使用符號v0表示。

  • mass:彈簧系統的質量(m)是指整個彈簧系統的質量,包括彈簧本身的質量以及彈簧上的附加物體的質量。

  • stiffness:彈簧系統的剛度(k)是指彈簧的彈性係數,表示彈簧單位伸長或壓縮時所產生的力的大小。剛度越大,彈簧的伸長或壓縮程度對應的力就越大。

  • damping:阻尼(d)是指彈簧系統中存在的阻礙物體振動的阻力。阻尼可以分為無阻尼、欠阻尼和過阻尼三種情況。無阻尼情況下,彈簧系統會進行自由振動;欠阻尼情況下,彈簧系統會有振幅逐漸減小的振動;過阻尼情況下,彈簧系統會有更加緩慢的振動。

案例:

import curves from '@ohos.curves';
@Entry
@Component
struct SpringTest {
  @State translateX: number = 0;

  private jumpWithSpeed(speed: number) {
    this.translateX = -1;
    animateTo({ duration: 2000, curve: curves.springCurve(speed, 1, 1, 1.2) }, () => {
      // 以指定初速度進行x方向的平移的彈簧動畫
      this.translateX = 0;
    })
  }

  build() {
    Column() {
      Button("button")
        .fontSize(14)
        .width(100)
        .height(50)
        .margin(30)
        .translate({ x: this.translateX })
      Row({space:50}) {
        Button("jump 50").fontSize(14)
          .onClick(() => {
            // 以初速度50的彈簧曲線進行平移
            this.jumpWithSpeed(50);
          })
        Button("jump 200").fontSize(14)
          .onClick(() => {
            // 以初速度200的彈簧曲線進行平移
            this.jumpWithSpeed(200);
          })
      }.margin(30)
    }.height('100%').width('100%')
  }
}

image

🔎2.使用springMotion和responsiveSpringMotion

springMotion和responsiveSpringMotion的介面為:

springMotion(response?: number, dampingFraction?: number, overlapDuration?: number)

responsiveSpringMotion(response?: number, dampingFraction?: number, overlapDuration?: number)
  • response:彈簧自然振動週期是指在沒有外力作用下,彈簧系統從一個極限位置到達另一個極限位置所需要的時間。它可以用公式T =2π√(m/k)來計算,其中T表示自然振動週期,m表示彈簧系統的質量,k表示彈簧的剛度。

  • dampingFraction:阻尼係數是指彈簧系統中阻尼的大小,用符號β表示。它可以分為三種情況:無阻尼(β = 0),欠阻尼(β < 2√(mk)),過阻尼(β > 2√(mk))。阻尼係數越大,彈簧系統的振動越快地衰減。

  • overlapDuration:彈性動畫銜接時長是指在動畫製作中,兩個物體之間由於彈性作用而發生的變形或運動的過程中所需要的時間。這個時長可以透過調整動畫的幀率和物體的彈性特性來控制,使得動畫看起來更加流暢和自然。

import curves from '@ohos.curves';

@Entry
@Component
struct SpringMotionTest {
  @State positionX: number = 100;
  @State positionY: number = 100;
  diameter: number = 50;

  build() {
    Column() {
      Row() {
        Circle({ width: this.diameter, height: this.diameter })
          .fill(Color.Blue)
          .position({ x: this.positionX, y: this.positionY })
          .onTouch((event: TouchEvent) => {
            if (event.type === TouchType.Move) {
              // 跟手過程,使用responsiveSpringMotion曲線
              animateTo({ curve: curves.responsiveSpringMotion() }, () => {
                // 減去半徑,以使球的中心運動到手指位置
                this.positionX = event.touches[0].screenX - this.diameter / 2;
                this.positionY = event.touches[0].screenY - this.diameter / 2;
                console.info(`move, animateTo x:${this.positionX}, y:${this.positionY}`);
              })
            } else if (event.type === TouchType.Up) {
              // 離手時,使用springMotion曲線
              animateTo({ curve: curves.springMotion() }, () => {
                this.positionX = 100;
                this.positionY = 100;
                console.info(`touchUp, animateTo x:100, y:100`);
              })
            }
          })
      }
      .width("100%").height("80%")
      .clip(true) // 如果球超出父元件範圍,使球不可見
      .backgroundColor(Color.Orange)

      Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Center }) {
        Text("拖動小球").fontSize(16)
      }
      .width("100%")

      Row() {
        Text('點選位置: [x: ' + Math.round(this.positionX) + ', y:' + Math.round(this.positionY) + ']').fontSize(16)
      }
      .padding(10)
      .width("100%")
    }.height('100%').width('100%')
  }
}

image

跟手過程推薦使用responsiveSpringMotion曲線,鬆手過程推薦使用springMotion曲線。跟手過程隨著手的位置變化會被多次觸發,所以會接連啟動多次responsiveSpringMotion動畫,鬆手時啟動一次springMotion動畫。

🚀寫在最後

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

image

相關文章