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

【引言】(完整代码在最后面)
本文将介绍如何在鸿蒙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的更多相关文章
- vue自定义组件(vue.use(),install)+全局组件+局部组件
相信大家都用过element-ui.mintui.iview等诸如此类的组件库,具体用法请参考:https://www.cnblogs.com/wangtong111/p/11522520.html ...
- vue2 自定义全局组件(Loading加载效果)
vue2 自定义全局组件(Loading加载效果) github地址: https://github.com/ccyinghua/custom-global-component 一.构建项目 vue ...
- 【全网首发】鸿蒙开源三方组件--强大的弹窗库XPopup组件
目录: 1.介绍 2.效果一览 3.依赖 4.如何使用 5.下载链接 6.<鸿蒙开源三方组件>文章合集 1. 介绍 XPopup是一个弹窗库,可能是Harmony平台最好的弹窗库.它从 ...
- vue中自定义组件(插件)
vue中自定义组件(插件) 原创 2017年01月04日 22:46:43 标签: 插件 在vue项目中,可以自定义组件像vue-resource一样使用Vue.use()方法来使用,具体实现方法: ...
- [转] vue自定义组件(通过Vue.use()来使用)即install的使用
在vue项目中,我们可以自定义组件,像element-ui一样使用Vue.use()方法来使用,具体实现方法: 1.首先新建一个Cmponent.vue文件 // Cmponent.vue<te ...
- 微信小程序入坑之自定义组件
前言 最近接触微信小程序,再次之前公司用的前端框架是vue ,然后对比发现,开发小程序是各种限制,对于开发者非常不友好.各种槽点太多,完全吐槽不过来,所以在此不多说,打算下次专门写一篇文章吐槽一下.本 ...
- Writing Your Own Widget(自定义组件)
英文地址:http://dojotoolkit.org/reference-guide/1.10/quickstart/writingWidgets.html#quickstart-writingwi ...
- vue自定义组件(通过Vue.use()来使用)即install的使用
在vue项目中,我们可以自定义组件,像element-ui一样使用Vue.use()方法来使用,具体实现方法: 1.首先新建一个loading.vue文件 // Cmponent.vue <te ...
- Android开发之自定义组件和接口回调
说到自定义控件不得不提的就是接口回调,在Android开发中接口回调用的还是蛮多的.在这篇博客开始的时候呢,我想聊一下iOS的自定义控件.在iOS中自定义控件的思路是继承自UIView, 在UIVie ...
- Android自定义组件
[参考的原文地址] http://blog.csdn.net/l1028386804/article/details/47101387效果图: 实现方式: 一:自定义一个含有EditText和Butt ...
随机推荐
- Linux 安装 TeX Live
安装新版本 cd /tmp # 下载安装压缩包 wget https://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz # 解 ...
- 【YashanDB知识库】filter or改写问题
问题现象 当filter中出现or的时候,会导致filter无法走索引或者走hash join,就需要进行改写,例如: create table test_tab1(col1 int, col2 in ...
- sicp每日一题[1.41]
Exercise 1.41 Define a procedure double that takes a procedure of one argument as argument and retur ...
- 6.24Win&linux&分析后门 勒索病毒分析
操作系统应急响应 1.常见危害 暴力破解.漏洞利用.流量攻击(危害不确定) 木马控制(Webshell.PC木马等),病毒感染(挖矿.蠕虫.勒索等) 2.常见分析 计算机用户.端口.进程.启动项.计划 ...
- LinkedHashMap原理详解—从LRU缓存机制说起
写在前面 从一道Leetcode题目说起 首先,来看一下Leetcode里面的一道经典题目:146.LRU缓存机制,题目描述如下: 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结 ...
- CSS & JS Effect – fade in
参考: stackoverflow – Is there a CSS-only (pure CSS) workaround to apply fade-in and fade-out on objec ...
- migration to end point routing
花了几个小时,记入一下吧. 1. odata https://devblogs.microsoft.com/odata/enabling-endpoint-routing-in-odata/ 找着弄就 ...
- CSS – 单侧环境 (stylelint, prettier, tailwind)
前言 真实项目中, 通常搭配 Webpack 之类的工具使用: Webpack 学习笔记 这篇记入的是单元测试的环境 参考: Get started with Tailwind CSS Automat ...
- Spring —— AOP(面向切面编程)
AOP(Aspect Oriented Programming)简介 面向切面编程,一种编程范式,指导开发者如何组织程序结构 作用:在不惊动原始设计的基础上为其进行功能增强 Spring理念:无入侵式 ...
- Java项目笔记(二)
一.分页待解决的问题 分页是在service层实现的 在controller层和service层同时写了这句代码 PageHelper.startPage(Integer.valueOf(pageNo ...