首页 > 其他分享 >鸿蒙NEXT自定义组件:太极Loading

鸿蒙NEXT自定义组件:太极Loading

时间:2024-11-15 20:56:15浏览次数:1  
标签:cellWidth Loading 自定义 Color px NEXT width backgroundColor height

 

【引言】(完整代码在最后面)

本文将介绍如何在鸿蒙NEXT中创建一个自定义的“太极Loading”组件,为你的应用增添独特的视觉效果。

【环境准备】

电脑系统:windows 10

开发工具:DevEco Studio NEXT Beta1 Build Version: 5.0.3.806

工程版本:API 12

真机:mate60 pro

语言:ArkTS、ArkUI

【项目分析】

1. 组件结构

我们将创建一个名为 TaiChiLoadingProgress 的自定义组件,它将模拟太极图的旋转效果,作为加载动画展示给用户。组件的基本结构如下:

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

2. 绘制太极图案

使用鸿蒙NEXT提供的UI组件,如 Rect 和 Circle,构建太极图的黑白两部分。关键在于利用 rotate 方法实现太极图的旋转效果。

build() {
  Stack() {
    Stack() {
      // 黑色半圆背景
      Stack() {
        Rect().width(`${this.cellWidth}px`).height(`${this.cellWidth / 2}px`).backgroundColor(Color.Black)
      }.width(`${this.cellWidth}px`).height(`${this.cellWidth}px`).rotate({ angle: -90 }).align(Alignment.Top)
      // 大黑球 上
      Stack() {
        Circle().width(`${this.cellWidth / 2}px`).height(`${this.cellWidth / 2}px`).fill(Color.Black)
        Circle().width(`${this.cellWidth / 8}px`).height(`${this.cellWidth / 8}px`).fill(Color.White)
      }.width(`${this.cellWidth}px`).height(`${this.cellWidth}px`).align(Alignment.Top)
      // 大白球 下
      Stack() {
        Circle().width(`${this.cellWidth / 2}px`).height(`${this.cellWidth / 2}px`).fill(Color.White)
        Circle().width(`${this.cellWidth / 8}px`).height(`${this.cellWidth / 8}px`).fill(Color.Black)
      }.width(`${this.cellWidth}px`).height(`${this.cellWidth}px`).align(Alignment.Bottom)
    }
    .width(`${this.cellWidth}px`)
    .height(`${this.cellWidth}px`)
    .borderWidth(1)
    .borderColor(Color.Black)
    .borderRadius('50%')
    .backgroundColor(Color.White)
    .clip(true)
    .rotate({
      angle: this.angle
    })
    .onVisibleAreaChange([0.0, 1.0], (isVisible: boolean, currentRatio: number) => {
      if (isVisible && currentRatio >= 1.0) {
        this.startAnim()
      }
      if (!isVisible && currentRatio <= 0.0) {
        this.endAnim()
      }
    })
  }
  .width(`${this.taiChiWidth}px`)
  .height(`${this.taiChiWidth}px`)
}

3. 动画实现

通过 animateTo 方法设置太极图的旋转动画,可以自定义动画曲线以实现不同的动画效果。

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

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

【完整代码】

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

  animationCurveChanged() {
    this.endAnim()
    this.startAnim()
  }

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

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

  aboutToAppear(): void {
    this.cellWidth = this.taiChiWidth / 2
  }

  build() {
    Stack() {
      Stack() {
        //黑色 半圆 背景
        Stack() {
          Rect().width(`${this.cellWidth}px`).height(`${this.cellWidth / 2}px`).backgroundColor(Color.Black)
        }.width(`${this.cellWidth}px`).height(`${this.cellWidth}px`).rotate({ angle: -90 }).align(Alignment.Top)

        //大黑球 上
        Stack() {
          Stack() {
            Circle().width(`${this.cellWidth / 2}px`).height(`${this.cellWidth / 2}px`).fill(Color.Black)
            Circle().width(`${this.cellWidth / 8}px`).height(`${this.cellWidth / 8}px`).fill(Color.White)
          }
        }.width(`${this.cellWidth}px`).height(`${this.cellWidth}px`).align(Alignment.Top)

        //大白球 下
        Stack() {
          Stack() {
            Circle().width(`${this.cellWidth / 2}px`).height(`${this.cellWidth / 2}px`).fill(Color.White)
            Circle().width(`${this.cellWidth / 8}px`).height(`${this.cellWidth / 8}px`).fill(Color.Black)
          }
        }.width(`${this.cellWidth}px`).height(`${this.cellWidth}px`).align(Alignment.Bottom)

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

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

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

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

      Text('官方Loading组件')
      Column() {
        LoadingProgress().width(this.loadingWidth)
          .visibility(this.isShowLoading ? Visibility.Visible : Visibility.None)
      }.height(this.loadingWidth).width(this.loadingWidth)

      Text('自定义太极Loading组件')
      Column() {
        TaiChiLoadingProgress({ taiChiWidth: vp2px(this.loadingWidth), animationCurve: this.animationCurve })
          .visibility(this.isShowLoading ? Visibility.Visible : Visibility.Hidden)
      }.height(this.loadingWidth).width(this.loadingWidth)

      Row() {
        Flex({ wrap: FlexWrap.Wrap }) {
          Text('显示/隐藏')
            .textAlign(TextAlign.Center)
            .width('200lpx')
            .height('200lpx')
            .margin('10lpx')
            .backgroundColor(Color.Black)
            .borderRadius(5)
            .backgroundColor(Color.Orange)
            .fontColor(Color.White)
            .clickEffect({ level: ClickEffectLevel.LIGHT })
            .onClick(() => {
              this.isShowLoading = !this.isShowLoading
            })
          Text('Linear动画')
            .textAlign(TextAlign.Center)
            .width('200lpx')
            .height('200lpx')
            .margin('10lpx')
            .backgroundColor(Color.Black)
            .borderRadius(5)
            .backgroundColor(Color.Orange)
            .fontColor(Color.White)
            .clickEffect({ level: ClickEffectLevel.LIGHT })
            .onClick(() => {
              this.animationCurve = Curve.Linear
            })
          Text('FastOutLinearIn动画')
            .textAlign(TextAlign.Center)
            .width('200lpx')
            .height('200lpx')
            .margin('10lpx')
            .backgroundColor(Color.Black)
            .borderRadius(5)
            .backgroundColor(Color.Orange)
            .fontColor(Color.White)
            .clickEffect({ level: ClickEffectLevel.LIGHT })
            .onClick(() => {
              this.animationCurve = Curve.FastOutLinearIn
            })
          Text('EaseIn动画')
            .textAlign(TextAlign.Center)
            .width('200lpx')
            .height('200lpx')
            .margin('10lpx')
            .backgroundColor(Color.Black)
            .borderRadius(5)
            .backgroundColor(Color.Orange)
            .fontColor(Color.White)
            .clickEffect({ level: ClickEffectLevel.LIGHT })
            .onClick(() => {
              this.animationCurve = Curve.EaseIn
            })
          Text('EaseOut动画')
            .textAlign(TextAlign.Center)
            .width('200lpx')
            .height('200lpx')
            .margin('10lpx')
            .backgroundColor(Color.Black)
            .borderRadius(5)
            .backgroundColor(Color.Orange)
            .fontColor(Color.White)
            .clickEffect({ level: ClickEffectLevel.LIGHT })
            .onClick(() => {
              this.animationCurve = Curve.EaseOut
            })
          Text('EaseInOut动画')
            .textAlign(TextAlign.Center)
            .width('200lpx')
            .height('200lpx')
            .margin('10lpx')
            .backgroundColor(Color.Black)
            .borderRadius(5)
            .backgroundColor(Color.Orange)
            .fontColor(Color.White)
            .clickEffect({ level: ClickEffectLevel.LIGHT })
            .onClick(() => {
              this.animationCurve = Curve.EaseInOut
            })
        }.width('660lpx')
      }.width('100%').justifyContent(FlexAlign.Center)
    }
    .height('100%')
    .width('100%')
    .backgroundColor("#f9feff")
  }
}

  

标签:cellWidth,Loading,自定义,Color,px,NEXT,width,backgroundColor,height
From: https://www.cnblogs.com/zhongcx/p/18548639

相关文章

  • 自定义注解进行数据脱敏
    前言有些时候,我们可能对输出的某些字段要做特殊的处理在输出到前端,比如:身份证号,电话等信息,在前端展示的时候我们需要进行脱敏处理,这时候通过自定义注解就非常的有用了。在Jackson中要自定义注解,我们可以通过@JacksonAnnotationsInside注解来实现,如下示例:一、自定义注解import......
  • go fiber: 抛出自定义异常
    一,代码:1,自定义错误类:packageconfigimport("fmt")//定义错误代码和错误信息typeMyErrorstruct{CodeintMsgstring}//需要定义通用的Error()方法func(eMyError)Error()string{returnfmt.Sprintf("Code:%d,Msg:%s",e.Code,e.M......
  • 分布式管理进阶:HarmonyOS Next 中的设备信息查询与状态监听
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。在探索HarmonyOSNext的分布式管理服务时......
  • 初识 HarmonyOS Next 的分布式管理:设备发现与认证
    初识HarmonyOSNext的分布式管理:设备发现与认证本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及......
  • HarmonyOS Next分布式管理核心功能解析:网络服务和数据传输的实现一
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。在HarmonyOSNext的分布式管理体系中,网络......
  • HarmonyOS Next 分布式管理权限控制:安全与隐私
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。在当今数字化时代,安全与隐私如同基石般重......
  • 织梦自定义图片字段报错 Call to a member function GetInnerText()
    问题:添加自定义图片字段时,前台打开当前栏目列表出现 Fatalerror:CalltoamemberfunctionGetInnerText()onstring 错误。解决方法:修改 customfields.func.php 文件:打开 /include/customfields.func.php 文件,搜索:  $fvalue=trim($ntag->GetInnerTe......
  • 鸿蒙NEXT应用示例:切换图片动画
     【引言】在鸿蒙NEXT应用开发中,实现图片切换动画是一项常见的需求。本文将介绍如何使用鸿蒙应用框架中的组件和动画功能,实现不同类型的图片切换动画效果。【环境准备】电脑系统:windows10开发工具:DevEcoStudioNEXTBeta1BuildVersion:5.0.3.806工程版本:API12真机:ma......
  • 鸿蒙NEXT开发案例:年龄计算
     ​【引言】本案例的目标是开发一款年龄计算器应用,该应用能够根据用户输入的出生日期,计算出用户的实际年龄、虚岁、星座、生肖等信息。同时,应用还将提供距离下次公历和农历生日的天数及星期等信息。为了实现这些功能,我们将使用ArkTS和ArkUI作为开发语言,并借助@nutpi/calendar......
  • ABB AC900F学习笔记331:使用ST做自定义功能块,计算最近60秒的分钟均值和最近60分钟的小
    前面自己学习了在西门子TIA使用SCL编程,施耐德Unity中使用ST编程做分钟均值和小时均值的方法,今晚在家练习了在ABBFreelance中自定义功能块使用ST语言做分钟均值和小时均值。新建项目、插入硬件、仿真器、操作站等不做介绍。新建一个用户功能块池,下面建一个功能块类。功能块类定......