Location>code7788 >text

Hongmeng NEXT Custom Components: Taiji Loading

Popularity:232 ℃/2024-11-15 21:10:32

 

[quote] (full code at the end)

In this article, we will introduce how to create a customized "Taiji Loading" component in Hongmeng NEXT to add unique visual effects to your application.

[Environmental Preparation]

Computer system: windows 10

Development Tools: DevEco Studio NEXT Beta1 Build Version: 5.0.3.806

Engineering version: API 12

The real one: mate60 pro

Languages: ArkTS, ArkUI

[Project analysis]

1. Component structure

We will create a custom component called TaiChiLoadingProgress that will simulate the rotation effect of the Tai Chi diagram and show it to the user as a loading animation. The basic structure of the component is as follows:

@Component
struct TaiChiLoadingProgress {
  @Prop taiChiWidth: number = 400
  @Prop @Watch('animationCurveChanged') animationCurve: Curve = 
  @State angle: number = 0
  @State cellWidth: number = 0
  ...
}

2. Drawing Taiji patterns

Use the UI components provided by Hongmeng NEXT, such as Rect and Circle, to build the black and white parts of the Tai Chi diagram. The key is to use the rotate method to realize the rotation effect of the Tai Chi diagram.

build() {
  Stack() {
    Stack() {
      // Black Half Circle Background
      Stack() {
        Rect().width(`${}px`).height(`${ / 2}px`).backgroundColor()
      }.width(`${}px`).height(`${}px`).rotate({ angle: -90 }).align()
      // Big Black Balls Up
      Stack() {
        Circle().width(`${ / 2}px`).height(`${ / 2}px`).fill()
        Circle().width(`${ / 8}px`).height(`${ / 8}px`).fill()
      }.width(`${}px`).height(`${}px`).align()
      // Under the Great White Ball
      Stack() {
        Circle().width(`${ / 2}px`).height(`${ / 2}px`).fill()
        Circle().width(`${ / 8}px`).height(`${ / 8}px`).fill()
      }.width(`${}px`).height(`${}px`).align()
    }
    .width(`${}px`)
    .height(`${}px`)
    .borderWidth(1)
    .borderColor()
    .borderRadius('50%')
    .backgroundColor()
    .clip(true)
    .rotate({
      angle: 
    })
    .onVisibleAreaChange([0.0, 1.0], (isVisible: boolean, currentRatio: number) => {
      if (isVisible && currentRatio >= 1.0) {
        ()
      }
      if (!isVisible && currentRatio <= 0.0) {
        ()
      }
    })
  }
  .width(`${}px`)
  .height(`${}px`)
}

3. Animation realization

Set the rotation animation of the Tai Chi diagram by animateTo method, you can customize the animation curve to achieve different animation effects.

startAnim() {
  animateTo({
    duration: 2000,
    iterations: -1,
    curve: 
  }, () => {
     = 360 * 2
  })
}

endAnim() {
  animateTo({
    duration: 0
  }, () => {
     = 0
  })
}

[complete code]

@Component
struct TaiChiLoadingProgress {
  @Prop taiChiWidth: number = 400
  @Prop @Watch('animationCurveChanged') animationCurve: Curve = 
  @State angle: number = 0
  @State cellWidth: number = 0

  animationCurveChanged() {
    ()
    ()
  }

  startAnim() {
    animateTo({
      duration: 2000,
      iterations: -1,
      curve: 
    }, () => {
       = 360 * 2
    })
  }

  endAnim() {
    animateTo({
      duration: 0
    }, () => {
       = 0
    })
  }

  aboutToAppear(): void {
     =  / 2
  }

  build() {
    Stack() {
      Stack() {
        //Black Semicircle Background
        Stack() {
          Rect().width(`${}px`).height(`${ / 2}px`).backgroundColor()
        }.width(`${}px`).height(`${}px`).rotate({ angle: -90 }).align()

        //Big Black Ball Up
        Stack() {
          Stack() {
            Circle().width(`${ / 2}px`).height(`${ / 2}px`).fill()
            Circle().width(`${ / 8}px`).height(`${ / 8}px`).fill()
          }
        }.width(`${}px`).height(`${}px`).align()

        /Big White Ball Down
        Stack() {
          Stack() {
            Circle().width(`${ / 2}px`).height(`${ / 2}px`).fill()
            Circle().width(`${ / 8}px`).height(`${ / 8}px`).fill()
          }
        }.width(`${}px`).height(`${}px`).align()

      }
      .width(`${}px`)
      .height(`${}px`)
      .borderWidth(1)
      .borderColor()
      .borderRadius('50%')
      .backgroundColor()
      .clip(true)
      .rotate({
        angle: 
      })
      .onVisibleAreaChange([0.0, 1.0], (isVisible: boolean, currentRatio: number) => {
        ('Test Row isVisible:' + isVisible + ', currentRatio:' + currentRatio)
        if (isVisible && currentRatio >= 1.0) {
          ('Test Row is fully visible.')
          ()
        }

        if (!isVisible && currentRatio <= 0.0) {
          ('Test Row is completely invisible.')
          ()
        }
      })
    }
    .width(`${}px`)
    .height(`${}px`)
  }
}

@Entry
@Component
struct Page08 {
  @State loadingWidth: number = 150
  @State isShowLoading: boolean = true;
  @State animationCurve: Curve = 

  build() {
    Column({ space: 20 }) {

      Text('Official Loading Component')
      Column() {
        LoadingProgress().width()
          .visibility( ?  : )
      }.height().width()

      Text('Customize Taiji Loading Component')
      Column() {
        TaiChiLoadingProgress({ taiChiWidth: vp2px(), animationCurve:  })
          .visibility( ?  : )
      }.height().width()

      Row() {
        Flex({ wrap:  }) {
          Text('Show/Hide')
            .textAlign()
            .width('200lpx')
            .height('200lpx')
            .margin('10lpx')
            .backgroundColor()
            .borderRadius(5)
            .backgroundColor()
            .fontColor()
            .clickEffect({ level:  })
            .onClick(() => {
               = !
            })
          Text('Linear animation')
            .textAlign()
            .width('200lpx')
            .height('200lpx')
            .margin('10lpx')
            .backgroundColor()
            .borderRadius(5)
            .backgroundColor()
            .fontColor()
            .clickEffect({ level:  })
            .onClick(() => {
               = 
            })
          Text('FastOutLinearIn Animation')
            .textAlign()
            .width('200lpx')
            .height('200lpx')
            .margin('10lpx')
            .backgroundColor()
            .borderRadius(5)
            .backgroundColor()
            .fontColor()
            .clickEffect({ level:  })
            .onClick(() => {
               = 
            })
          Text('EaseIn Animation')
            .textAlign()
            .width('200lpx')
            .height('200lpx')
            .margin('10lpx')
            .backgroundColor()
            .borderRadius(5)
            .backgroundColor()
            .fontColor()
            .clickEffect({ level:  })
            .onClick(() => {
               = 
            })
          Text('EaseOut Animation')
            .textAlign()
            .width('200lpx')
            .height('200lpx')
            .margin('10lpx')
            .backgroundColor()
            .borderRadius(5)
            .backgroundColor()
            .fontColor()
            .clickEffect({ level:  })
            .onClick(() => {
               = 
            })
          Text('EaseInOut Animation')
            .textAlign()
            .width('200lpx')
            .height('200lpx')
            .margin('10lpx')
            .backgroundColor()
            .borderRadius(5)
            .backgroundColor()
            .fontColor()
            .clickEffect({ level:  })
            .onClick(() => {
               = 
            })
        }.width('660lpx')
      }.width('100%').justifyContent()
    }
    .height('100%')
    .width('100%')
    .backgroundColor("#f9feff")
  }
}