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

本文将介绍如何在鸿蒙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")
}
}

  

鸿蒙NEXT自定义组件:太极Loading的更多相关文章

  1. vue自定义组件(vue.use(),install)+全局组件+局部组件

    相信大家都用过element-ui.mintui.iview等诸如此类的组件库,具体用法请参考:https://www.cnblogs.com/wangtong111/p/11522520.html ...

  2. vue2 自定义全局组件(Loading加载效果)

    vue2 自定义全局组件(Loading加载效果) github地址: https://github.com/ccyinghua/custom-global-component 一.构建项目 vue ...

  3. 【全网首发】鸿蒙开源三方组件--强大的弹窗库XPopup组件

    目录: 1.介绍 2.效果一览 3.依赖 4.如何使用 5.下载链接 6.<鸿蒙开源三方组件>文章合集 1. 介绍 ​ XPopup是一个弹窗库,可能是Harmony平台最好的弹窗库.它从 ...

  4. vue中自定义组件(插件)

    vue中自定义组件(插件) 原创 2017年01月04日 22:46:43 标签: 插件 在vue项目中,可以自定义组件像vue-resource一样使用Vue.use()方法来使用,具体实现方法: ...

  5. [转] vue自定义组件(通过Vue.use()来使用)即install的使用

    在vue项目中,我们可以自定义组件,像element-ui一样使用Vue.use()方法来使用,具体实现方法: 1.首先新建一个Cmponent.vue文件 // Cmponent.vue<te ...

  6. 微信小程序入坑之自定义组件

    前言 最近接触微信小程序,再次之前公司用的前端框架是vue ,然后对比发现,开发小程序是各种限制,对于开发者非常不友好.各种槽点太多,完全吐槽不过来,所以在此不多说,打算下次专门写一篇文章吐槽一下.本 ...

  7. Writing Your Own Widget(自定义组件)

    英文地址:http://dojotoolkit.org/reference-guide/1.10/quickstart/writingWidgets.html#quickstart-writingwi ...

  8. vue自定义组件(通过Vue.use()来使用)即install的使用

    在vue项目中,我们可以自定义组件,像element-ui一样使用Vue.use()方法来使用,具体实现方法: 1.首先新建一个loading.vue文件 // Cmponent.vue <te ...

  9. Android开发之自定义组件和接口回调

    说到自定义控件不得不提的就是接口回调,在Android开发中接口回调用的还是蛮多的.在这篇博客开始的时候呢,我想聊一下iOS的自定义控件.在iOS中自定义控件的思路是继承自UIView, 在UIVie ...

  10. Android自定义组件

    [参考的原文地址] http://blog.csdn.net/l1028386804/article/details/47101387效果图: 实现方式: 一:自定义一个含有EditText和Butt ...

随机推荐

  1. C++11新特性(一):语言特性

    C++11新特性 总结C++11特性时发现整个内容角度,建议查看前先查看目录. 语言特性 右值引用 右值的分类为将亡值和字面量.将亡值就是将要销毁的对象以及临时的变量,字面量就是常量.左值就是变量. ...

  2. 安装部署harbor

    配置文件中修改内容hostname 和 证书 私钥 需要指定到文件 hostname: hub.rainsc.com # http related config http: # port for ht ...

  3. 最详细STL(四)priority_queue

    好吧,开始累了,不想写那么多废话了,直接讲对打oj有用的部分吧. priority_queue是由堆来实现的,底层是用vector来实现的,接收三个参数 priority_queue<int , ...

  4. Go plan9 汇编:手写汇编

    原创文章,欢迎转载,转载请注明出处,谢谢. 0. 前言 在 Go plan9 汇编: 打通应用到底层的任督二脉 一文中介绍了从应用程序到汇编指令的转换.本文将结合汇编和 Go 程序实现手写基本的汇编指 ...

  5. java 知识

    1. 单文件java 例子和简单项目例子 http://kleinfelter.com/java-hello-world-with-visual-studio-code-and-eclipse jav ...

  6. kubernetes删除ns异常状态为:Terminating

    在部署kuboard控制平台的时候,不规范删除,导致ns状态为Terminating [root@master01 ~]# kubectl delete namespace kuboard ^C ro ...

  7. 如何将图片转换为向量?(通过DashScope API调用)

    本文介绍如何通过模型服务灵积DashScope将 图片转换为向量 ,并入库至向量检索服务DashVector中进行向量检索. 模型服务灵积DashScope,通过灵活.易用的模型API服务,让各种模态 ...

  8. 从零开始搭建一个LoRaWAN基站

    先说两句 SX1301/SX1302是semtech公司推出的基站端射频基带芯片,其与SX127x/SX126x的主要区别在于: 只是个基带芯片,使用时需要加射频前端(SX125x/SAW/...) ...

  9. 【ARMv8基础篇】CCI-400控制器简介

    CCI(Cache Coherent Interconnect)是ARM中的cache一致性控制器. CCI-400将互连和一致性功能结合到一个模块中.它支持多达两个ACE 主节点的连接,例如: Co ...

  10. 07 - react 唯一修改state状态的方式 setState

    // setState 修改状态 如果是直接修改页面不会改变 使用 setState 修改数据 才会驱动视图的改变 // setState 的原理:修改玩状态之后会调用 render 函数 impor ...