先上效果图
直播点赞.jpg
需求梳理
抖音APP中,视频的点赞和直播中点赞效果是不同的,先找寻两者的共同点提取接口:
类型 | 图片 | 动画 | 初始旋转角度 | Y轴偏移量 |
---|---|---|---|---|
视频点赞 | 单张红心 | 组合动画 | 随机旋转角度 | -50 |
直播点赞 | 多张图片随机 | 组合动画 | 无 | -20 |
Y轴偏移量是多次调试的,看各位同学需求,都可以调整。
interface ILikeFollowData {
/**
* 获取图标列表
*/
fun getIconList(): List<Any>
/**
* 获取图标大小
*/
fun getIconSize(): Int
/**
* 获取旋转角度范围
*/
fun getRotationRange(): IntRange
/**
* 获取Y轴偏移量
*/
fun getYOffset(): Int
/**
* 获取动画集合
*/
fun getAnimatorSet(view: View): AnimatorSet
}
实现
视频点赞数据类
class VideoLikeFollowData : ILikeFollowData {
private val iconList = arrayListOf<Any>(R.drawable.img_like_follow)
override fun getIconList() = iconList
override fun getIconSize() = 240
override fun getRotationRange() = -30..30
override fun getYOffset() = -50
override fun getAnimatorSet(view: View): AnimatorSet {
val set = AnimatorSet()
//放大
set.playSequentially(
AnimatorSet().apply {
playTogether(
ObjectAnimator.ofFloat(view, "scaleX", 1f, 1.4f).apply {
duration = 50
},
ObjectAnimator.ofFloat(view, "scaleY", 1f, 1.4f).apply {
duration = 50
},
)
},
//缩小
AnimatorSet().apply {
playTogether(
ObjectAnimator.ofFloat(view, "scaleX", 1.4f, 1f).apply {
duration = 200
},
ObjectAnimator.ofFloat(view, "scaleY", 1.4f, 1f).apply {
duration = 200
},
)
},
ValueAnimator.ofInt(0, 100).apply {
duration = 200
},
//缩放/透明并位移
AnimatorSet().apply {
playTogether(
ObjectAnimator.ofFloat(view, "scaleX", 1f, 1.8f).apply {
duration = 500
},
ObjectAnimator.ofFloat(view, "scaleY", 1f, 1.8f).apply {
duration = 500
},
ObjectAnimator.ofFloat(view, "alpha", 1f, 0f).apply {
duration = 500
},
ObjectAnimator.ofFloat(
view,
"translationY",
view.y,
view.y - 300f
).apply {
duration = 500
},
)
})
return set
}
}
直播点赞数据类
class LiveLikeFollowData : ILikeFollowData {
private val iconList = arrayListOf<Any>(
R.drawable.img_like_follow_1,
R.drawable.img_like_follow_2,
R.drawable.img_like_follow_3,
R.drawable.img_like_follow_4,
R.drawable.img_like_follow_5,
R.drawable.img_like_follow_6,
R.drawable.img_like_follow_7,
)
override fun getIconList() = iconList
override fun getIconSize() = 100
override fun getRotationRange() = 0..0
override fun getYOffset() = -20
override fun getAnimatorSet(view: View): AnimatorSet {
val set = AnimatorSet()
//放大
set.playSequentially(
AnimatorSet().apply {
// 同时播放
playTogether(
ObjectAnimator.ofFloat(view, "scaleX", 1f, 1.1f).apply {
duration = 50
},
ObjectAnimator.ofFloat(view, "scaleY", 1f, 1.1f).apply {
duration = 50
},
ObjectAnimator.ofFloat(view, "rotation", -20f, -6f).apply {
duration = 50
}
)
},
//缩小
AnimatorSet().apply {
playTogether(
ObjectAnimator.ofFloat(view, "scaleX", 1.1f, 1f).apply {
duration = 200
},
ObjectAnimator.ofFloat(view, "scaleY", 1.1f, 1f).apply {
duration = 200
},
ObjectAnimator.ofFloat(view, "rotation", -6f, 4f, 0f).apply {
duration = 200
}
)
},
ValueAnimator.ofInt(0, 100).apply {
duration = 200
},
//缩放/透明并位移
AnimatorSet().apply {
playTogether(
ObjectAnimator.ofFloat(view, "scaleX", 1f, 1.8f).apply {
duration = 500
},
ObjectAnimator.ofFloat(view, "scaleY", 1f, 1.8f).apply {
duration = 500
},
ObjectAnimator.ofFloat(view, "alpha", 1f, 0f).apply {
duration = 500
}
)
})
return set
}
}
上述代码中的图片,各位同学可以让UI自行设计切图,如果需要,可以在末尾代码链接处下载获取。
功能model
object LikeFollowModel {
//短视频展示数据
val videoLikeFollowData: ILikeFollowData by lazy {
VideoLikeFollowData()
}
//直播展示数据
val liveLikeFollowData: ILikeFollowData by lazy {
LiveLikeFollowData()
}
/**
* 展示点赞效果
* @param x: 点击的x坐标
* @param y: 点击的y坐标
* @param viewGroup: 父布局
* @param data: 展示数据
*/
fun show(x: Int, y: Int, viewGroup: ViewGroup, data: ILikeFollowData = videoLikeFollowData) {
//添加爱心
val likeView = AppCompatImageView(viewGroup.context)
//加载图片,封装的Glide方法,同学可自行处理
loadImage(likeView, data.getIconList().random())
val size = data.getIconSize()
val layoutParams = ViewGroup.LayoutParams(size, size)
likeView.layoutParams = layoutParams
//设置爱心位置
likeView.x = (x - (size / 2)).toFloat()
likeView.y = (y - size + data.getYOffset()).toFloat()
//设置随机旋转角度
likeView.rotation = (data.getRotationRange().random()).toFloat()
viewGroup.addView(likeView)
//获取动画集合
val animatorSet = data.getAnimatorSet(likeView)
//添加动画结束监听
animatorSet.addListener(onEnd = {
tryCatch({
//清理动画
likeView.clearAnimation()
//隐藏图片
likeView.visibility = View.GONE
//移除图片,延迟500毫秒移除,防止动画还没结束就移除
HandlerUtils.postRunnable({
viewGroup.removeView(likeView)
}, 500)
})
})
animatorSet.start()
}
}
以上四个类就是所有的功能代码。
实现思路还是蛮简单的:
实现思路.jpg
获取点击事件坐标
避免同学获取点击坐标有疑问,这里再补充上相关代码:
/**
* 设置点击监听
* 返回坐标
*/
@SuppressLint("ClickableViewAccessibility")
private fun setViewOnClickListener(view: View, clickCallBack: (x: Int, y: Int) -> Unit) {
var x = 0f
var y = 0f
view.setOnTouchListener { _, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
x = event.x
y = event.y
}
MotionEvent.ACTION_UP -> {
if (x == event.x && y == event.y) {
clickCallBack(event.x.toInt(), event.y.toInt())
}
}
}
true
}
}
网友评论