哔哩哔哩点赞与一键三连效果实现教程
本教程适合HarmonyOS初学者,通过简单到复杂的步骤,一步步实现类似哔哩哔哩APP中的点赞及一键三连效果。
最终效果预览
我们将实现以下两个效果:
- 点击点赞按钮:实现点赞/取消点赞的切换效果,包含图标变色和缩放动画
- 长按点赞按钮:实现一键三连效果,包含旋转、缩放和粒子动画
一、基础布局实现
首先,我们需要创建基本的界面布局。这一步非常简单,只需要放置一个点赞图标。
ts
@Entry
@Component
struct BilibiliLike {
build() {
// 使用Stack布局,使元素居中对齐
Stack({ alignContent: Alignment.Center }) {
// 点赞图标
Image($r('app.media.ic_public_like'))
.width(50) // 设置图标宽度
.aspectRatio(1) // 保持宽高比为1:1
.objectFit(ImageFit.Contain) // 设置图片适应方式
}
.width('100%') // 容器占满宽度
.height('100%') // 容器占满高度
.backgroundColor('#f1f1f1') // 设置背景颜色为浅灰色
}
}
这一步实现了最基础的布局,我们使用了Stack布局使元素居中,并添加了一个点赞图标。图标使用了系统资源$r('app.media.ic_public_like')
。
二、添加状态和颜色切换
接下来,我们添加状态变量来跟踪点赞状态,并实现点击时的颜色切换效果。
ts
@Entry
@Component
struct BilibiliLike {
// 是否已点赞状态
@State isLiked: boolean = false
// 未点赞时的颜色(灰色)
@State unlikeColor: string = '#757575'
// 点赞后的颜色(蓝色)
@State likeColor: string = '#4eabe6'
build() {
Stack({ alignContent: Alignment.Center }) {
Image($r('app.media.ic_public_like'))
.width(50)
.aspectRatio(1)
.objectFit(ImageFit.Contain)
.fillColor(this.isLiked ? this.likeColor : this.unlikeColor) // 根据点赞状态设置颜色
.onClick(() => {
// 点击时切换点赞状态
this.isLiked = !this.isLiked
})
}
.width('100%')
.height('100%')
.backgroundColor('#f1f1f1')
}
}
这一步我们添加了:
isLiked
状态变量,用于跟踪是否已点赞- 两个颜色变量
unlikeColor
和likeColor
- 在图标上添加
fillColor
属性,根据点赞状态切换颜色 - 为图标添加
onClick
事件,实现点击时切换点赞状态
现在点击图标时,图标会在灰色和蓝色之间切换,实现了基本的点赞/取消点赞效果。
三、添加点击动画效果
点击时的颜色变化已经实现了,但用户体验还不够好。我们需要添加一些动画效果,让点赞操作更加生动。
ts
@Entry
@Component
struct BilibiliLike {
@State isLiked: boolean = false
@State unlikeColor: string = '#757575'
@State likeColor: string = '#4eabe6'
// 添加控制缩放的状态变量
@State scaleValue: number = 1
build() {
Stack({ alignContent: Alignment.Center }) {
Image($r('app.media.ic_public_like'))
.width(50)
.aspectRatio(1)
.objectFit(ImageFit.Contain)
.fillColor(this.isLiked ? this.likeColor : this.unlikeColor)
.scale({ x: this.scaleValue, y: this.scaleValue }) // 添加缩放效果
.onClick(() => {
this.toggleLike() // 调用点赞切换方法
})
}
.width('100%')
.height('100%')
.backgroundColor('#f1f1f1')
}
// 处理点赞动画效果
toggleLike() {
// 切换点赞状态
this.isLiked = !this.isLiked
// 点赞动画 - 第一阶段:放大
animateTo({
duration: 300, // 动画持续300毫秒
curve: Curve.Friction, // 使用摩擦曲线,效果更自然
delay: 0 // 无延迟立即执行
}, () => {
this.scaleValue = 1.5 // 图标放大到1.5倍
})
// 点赞动画 - 第二阶段:恢复原大小
animateTo({
duration: 100, // 动画持续100毫秒
curve: Curve.Friction, // 使用摩擦曲线
delay: 300 // 延迟300毫秒执行,等第一阶段完成
}, () => {
this.scaleValue = 1 // 图标恢复到原始大小
})
}
}
这一步我们添加了:
scaleValue
状态变量,用于控制图标的缩放比例- 图标添加
scale
属性,绑定到scaleValue
状态 - 创建了
toggleLike
方法,实现点赞状态切换和动画效果 - 使用
animateTo
方法创建两段动画:先放大,再恢复原大小
现在点击图标时,不仅会变色,还会有一个放大再缩小的动画效果,让交互更加生动。
四、添加长按手势识别
接下来,我们要实现长按触发一键三连的功能,首先需要添加长按手势识别。
ts
@Entry
@Component
struct BilibiliLike {
@State isLiked: boolean = false
@State unlikeColor: string = '#757575'
@State likeColor: string = '#4eabe6'
@State scaleValue: number = 1
// 添加一个标记三连效果的状态
@State isTripleAction: boolean = false
build() {
Stack({ alignContent: Alignment.Center }) {
Image($r('app.media.ic_public_like'))
.width(50)
.aspectRatio(1)
.objectFit(ImageFit.Contain)
.fillColor(this.isLiked ? this.likeColor : this.unlikeColor)
.scale({ x: this.scaleValue, y: this.scaleValue })
// 添加长按手势
.gesture(
LongPressGesture({ repeat: false }) // 长按手势,不重复触发
.onAction(() => {
console.info("检测到长按事件")
// 设置状态
this.isTripleAction = true
this.isLiked = true
})
)
.onClick(() => {
this.toggleLike()
})
}
.width('100%')
.height('100%')
.backgroundColor('#f1f1f1')
}
// 点赞动画方法保持不变
toggleLike() {
// 代码同上...
}
}
这一步我们添加了:
isTripleAction
状态变量,用于标记是否触发了一键三连效果- 使用
gesture
方法添加长按手势识别 - 在长按触发时设置相关状态
现在,长按图标后,会将点赞状态设为已点赞,并触发三连状态,但还没有具体的动画效果。
五、添加长按动画效果
下一步,我们为长按添加更丰富的动画效果,包括旋转和缩放。
ts
@Entry
@Component
struct BilibiliLike {
@State isLiked: boolean = false
@State isTripleAction: boolean = false
@State scaleValue: number = 1
@State unlikeColor: string = '#757575'
@State likeColor: string = '#4eabe6'
// 添加旋转角度状态
@State rotation: number = 0
build() {
Stack({ alignContent: Alignment.Center }) {
Image($r('app.media.ic_public_like'))
.width(50)
.aspectRatio(1)
.objectFit(ImageFit.Contain)
.fillColor(this.isLiked ? this.likeColor : this.unlikeColor)
.scale({ x: this.scaleValue, y: this.scaleValue })
.rotate({ z: 1, angle: this.rotation }) // 添加旋转效果
.gesture(
LongPressGesture({ repeat: false })
.onAction(() => {
this.triggerTripleAction() // 调用三连效果方法
})
)
.onClick(() => {
this.toggleLike()
})
}
.width('100%')
.height('100%')
.backgroundColor('#f1f1f1')
}
// 点赞动画方法保持不变
toggleLike() {
// 代码同上...
}
// 处理一键三连动画效果
triggerTripleAction() {
// 设置三连状态和点赞状态
this.isTripleAction = true
this.isLiked = true
// 阶段一:点赞按钮放大并旋转
animateTo({
duration: 200, // 动画持续200毫秒
curve: Curve.EaseInOut // 使用缓入缓出曲线
}, () => {
this.scaleValue = 1.8 // 图标放大到1.8倍
this.rotation = 20 // 图标旋转20度
})
// 阶段二:点赞按钮缩小并恢复角度
animateTo({
duration: 100, // 动画持续100毫秒
curve: Curve.EaseInOut, // 使用缓入缓出曲线
delay: 200 // 延迟200毫秒,等阶段一完成
}, () => {
this.scaleValue = 1.2 // 图标缩小到1.2倍
this.rotation = 0 // 图标恢复原始角度
})
// 阶段三:点赞按钮恢复原始大小
animateTo({
duration: 100, // 动画持续100毫秒
curve: Curve.EaseInOut, // 使用缓入缓出曲线
delay: 300 // 延迟300毫秒,等阶段二完成
}, () => {
this.scaleValue = 1 // 图标恢复原始大小
})
// 重置三连状态
setTimeout(() => {
this.isTripleAction = false
}, 1000) // 延迟1000毫秒(1秒)执行
}
}
这一步我们添加了:
rotation
状态变量,用于控制图标的旋转角度- 图标添加
rotate
属性,实现旋转效果 - 创建了
triggerTripleAction
方法,实现三连动画效果 - 三段连续动画,实现放大旋转、缩小恢复的动画序列
现在,长按图标会触发一系列动画:图标先放大并顺时针旋转,然后缩小并恢复原始角度,最后恢复原始大小,整个过程非常流畅。
六、添加粒子爆炸效果
最后,我们添加粒子爆炸效果,让一键三连的视觉效果更加丰富。
ts
@Entry
@Component
struct BilibiliLike {
@State isLiked: boolean = false
@State isTripleAction: boolean = false
@State scaleValue: number = 1
@State rotation: number = 0
@State unlikeColor: string = '#757575'
@State likeColor: string = '#4eabe6'
// 添加粒子透明度状态
@State iconOpacity: number = 0
build() {
Stack({ alignContent: Alignment.Center }) {
// 粒子效果容器
Column() {
// 当触发三连效果时显示粒子
if (this.isTripleAction) {
// 创建8个粒子,均匀分布在圆周上
ForEach([1, 2, 3, 4, 5, 6, 7, 8], (item: number) => {
Circle()
.width(8) // 粒子宽度
.height(8) // 粒子高度
.fill(this.likeColor) // 使用点赞颜色填充粒子
// 使用三角函数计算粒子在圆周上的位置
.position({ x: 25 + 50 * Math.cos(item * Math.PI / 4), y: 25 + 50 * Math.sin(item * Math.PI / 4) })
.opacity(this.iconOpacity) // 控制粒子的透明度
})
}
}
.width(50) // 设置容器宽度
.height(50) // 设置容器高度
// 点赞按钮
Image($r('app.media.ic_public_like'))
.width(50)
.aspectRatio(1)
.objectFit(ImageFit.Contain)
.fillColor(this.isLiked ? this.likeColor : this.unlikeColor)
.scale({ x: this.scaleValue, y: this.scaleValue })
.rotate({ z: 1, angle: this.rotation })
.gesture(
LongPressGesture({ repeat: false })
.onAction(() => {
this.triggerTripleAction()
})
)
.onClick(() => {
this.toggleLike()
})
}
.width('100%')
.height('100%')
.backgroundColor('#f1f1f1')
}
// 点赞动画方法保持不变
toggleLike() {
// 代码同上...
}
// 处理一键三连动画效果
triggerTripleAction() {
// 设置三连状态和点赞状态
this.isTripleAction = true
this.isLiked = true
// 点赞按钮动画部分保持不变
// ...
// 添加粒子出现动画
animateTo({
duration: 500, // 动画持续500毫秒
curve: Curve.EaseOut, // 使用缓出曲线,开始快结束慢
delay: 200 // 延迟200毫秒执行
}, () => {
this.iconOpacity = 1 // 粒子透明度变为1,完全显示
})
// 粒子消失动画
animateTo({
duration: 300, // 动画持续300毫秒
curve: Curve.Linear, // 使用线性曲线,匀速变化
delay: 700 // 延迟700毫秒,等粒子完全显示一段时间
}, () => {
this.iconOpacity = 0 // 粒子透明度变为0,完全消失
})
// 重置三连状态
setTimeout(() => {
this.isTripleAction = false
}, 1000) // 延迟1000毫秒(1秒)执行
}
}
这一步我们添加了:
iconOpacity
状态变量,用于控制粒子的透明度- 在Stack中添加粒子效果容器
- 使用ForEach和条件渲染,当触发三连效果时创建并显示粒子
- 使用三角函数计算粒子在圆周上的位置
- 添加粒子的动画效果,包括出现和消失
七、完整实现
最后,我们来看一下最终的完整代码实现。这里整合了前面所有的步骤,并添加了一些额外的细节优化。
ts
/**
* 哔哩哔哩点赞和一键三连效果组件
* 实现功能:
* 1. 普通点击: 实现点赞/取消点赞效果
* 2. 长按: 触发一键三连效果(点赞+粒子动画)
*/
@Entry
@Component
struct BilibiliLike {
// 是否已点赞状态
@State isLiked: boolean = false
// 是否触发一键三连效果状态
@State isTripleAction: boolean = false
// 控制图标缩放比例
@State scaleValue: number = 1
// 控制图标透明度
@State opacityValue: number = 1
// 控制图标X轴偏移量
@State translateXValue: number = 0
// 控制图标Y轴偏移量
@State translateYValue: number = 0
// 控制图标旋转角度
@State rotation: number = 0
// 控制粒子效果透明度
@State iconOpacity: number = 0
// 未点赞时的颜色(灰色)
@State unlikeColor: string = '#757575'
// 点赞后的颜色(蓝色)
@State likeColor: string = '#4eabe6'
build() {
// 使用Stack布局,所有元素居中对齐
Stack({ alignContent: Alignment.Center }) {
// 粒子效果容器
Column() {
// 当触发三连效果时显示粒子
if (this.isTripleAction) {
// 创建8个粒子,均匀分布在圆周上
ForEach([1, 2, 3, 4, 5, 6, 7, 8], (item: number) => {
Circle()
.width(8) // 粒子宽度
.height(8) // 粒子高度
.fill(this.likeColor) // 使用点赞颜色填充粒子
// 使用三角函数计算粒子在圆周上的位置
.position({ x: 25 + 50 * Math.cos(item * Math.PI / 4), y: 25 + 50 * Math.sin(item * Math.PI / 4) })
.opacity(this.iconOpacity) // 控制粒子的透明度
})
}
}
.width(50) // 设置容器宽度
.height(50) // 设置容器高度
// 点赞按钮
Image($r('app.media.ic_public_like')) // 使用点赞图标资源
.width(50) // 设置图标宽度
.aspectRatio(1) // 保持宽高比为1:1
.objectFit(ImageFit.Contain) // 设置图片适应方式
.fillColor(this.isLiked ? this.likeColor : this.unlikeColor) // 根据点赞状态设置颜色
.scale({ x: this.scaleValue, y: this.scaleValue }) // 设置缩放值
.opacity(this.opacityValue) // 设置透明度
.rotate({ z: 1, angle: this.rotation }) // 设置旋转角度,绕z轴旋转
.translate({ x: this.translateXValue, y: this.translateYValue }) // 设置平移值
// 添加长按手势,触发一键三连效果
.gesture(
LongPressGesture({ repeat: false }) // 长按手势,不重复触发
.onAction(() => {
this.triggerTripleAction() // 调用三连效果方法
})
)
// 添加点击事件,触发普通点赞效果
.onClick(() => {
this.toggleLike() // 调用点赞切换方法
})
}
.width('100%') // 容器占满宽度
.height('100%') // 容器占满高度
.backgroundColor('#f1f1f1') // 设置背景颜色为浅灰色
.expandSafeArea() // 扩展到安全区域
}
/**
* 处理点赞/取消点赞动画效果
* 点击时切换点赞状态并播放放大缩小动画
*/
toggleLike() {
// 切换点赞状态
this.isLiked = !this.isLiked
// 点赞动画 - 第一阶段:放大
animateTo({
duration: 300, // 动画持续300毫秒
curve: Curve.Friction, // 使用摩擦曲线,效果更自然
delay: 0 // 无延迟立即执行
}, () => {
this.scaleValue = 1.5 // 图标放大到1.5倍
})
// 点赞动画 - 第二阶段:恢复原大小
animateTo({
duration: 100, // 动画持续100毫秒
curve: Curve.Friction, // 使用摩擦曲线
delay: 300 // 延迟300毫秒执行,等第一阶段完成
}, () => {
this.scaleValue = 1 // 图标恢复到原始大小
})
}
/**
* 处理一键三连动画效果
* 包含多个动画阶段:放大旋转、粒子出现与消失
*/
triggerTripleAction() {
// 设置三连状态和点赞状态
this.isTripleAction = true // 启用三连效果
this.isLiked = true // 设置为已点赞状态
// 阶段一:点赞按钮放大并旋转
animateTo({
duration: 200, // 动画持续200毫秒
curve: Curve.EaseInOut // 使用缓入缓出曲线
}, () => {
this.scaleValue = 1.8 // 图标放大到1.8倍
this.rotation = 20 // 图标旋转20度
})
// 阶段二:点赞按钮缩小并恢复角度
animateTo({
duration: 100, // 动画持续100毫秒
curve: Curve.EaseInOut, // 使用缓入缓出曲线
delay: 200 // 延迟200毫秒,等阶段一完成
}, () => {
this.scaleValue = 1.2 // 图标缩小到1.2倍
this.rotation = 0 // 图标恢复原始角度
})
// 阶段三:点赞按钮恢复原始大小
animateTo({
duration: 100, // 动画持续100毫秒
curve: Curve.EaseInOut, // 使用缓入缓出曲线
delay: 300 // 延迟300毫秒,等阶段二完成
}, () => {
this.scaleValue = 1 // 图标恢复原始大小
this.isLiked = true // 确保点赞状态为true
})
// 阶段四:粒子出现动画
animateTo({
duration: 500, // 动画持续500毫秒
curve: Curve.EaseOut, // 使用缓出曲线,开始快结束慢
delay: 200 // 延迟200毫秒执行
}, () => {
this.iconOpacity = 1 // 粒子透明度变为1,完全显示
})
// 阶段五:粒子消失动画
animateTo({
duration: 300, // 动画持续300毫秒
curve: Curve.Linear, // 使用线性曲线,匀速变化
delay: 700 // 延迟700毫秒,等粒子完全显示一段时间
}, () => {
this.iconOpacity = 0 // 粒子透明度变为0,完全消失
})
// 延时重置三连状态,完成整个动画周期
setTimeout(() => {
this.isTripleAction = false // 关闭三连效果状态
}, 1000) // 延迟1000毫秒(1秒)执行
}
}
拓展与优化
以上是基本的实现,如果想进一步优化,可以考虑:
- 添加声音效果:在点赞和三连时添加声音反馈
- 添加震动反馈:利用设备振动提供触觉反馈
- 优化粒子效果:使用更复杂的粒子系统,例如随机大小、颜色和速度
- 添加投币和收藏图标:真正实现完整的"一键三连"效果,显示投币和收藏图标
总结
通过这个教程,我们从零开始实现了哔哩哔哩的点赞和一键三连效果。主要用到了以下技术:
- HarmonyOS的ArkUI布局系统
- 状态管理(@State)
- 手势处理(点击、长按)
- 动画系统(animateTo)
- 条件渲染
- 数学计算(用于粒子位置)
这些技术和概念不仅适用于这个特定效果,还可以应用于各种交互设计中。希望这个教程能帮助你更好地理解HarmonyOS开发,并创建出更加精美的应用界面!