[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") } }