场景
实现直播房间点赞爱心动画(不是送礼物的动画)
难点:流畅的飘爱心
1. 方案1
直接使用animator做动画
参考资料: https://github.com/Yasic/QQBubbleView
1.1. 优化方向:
- 削峰
- 不要每次都inflate layout,尝试模拟listview的recycleBin 对用跑完动画的View 重新赋值初始化
2. 方案2:
直接在View上绘制爱心
参考资料:https://github.com/HomHomLin/Android-DivergeView
核心就是一个while循环,不断计算当前爱心的位置
while (mRunning) {
if (mQueen == null) {
continue;
}
if (mIsDrawing) {
//如果正在绘制,不要处理数据
continue;
}
dealQueen();
dealDiverge();
mIsDrawing = true;
postInvalidate();
}
在dealQueen里面处理正在等待走动画的点赞
if (mQueen.size() > 0 && now - mLastAddTime > mQueenDuration) {
mLastAddTime = System.currentTimeMillis();
DivergeInfo divergeInfo = null;
if (mDeadPool.size() > 0) {
//死池里面有空闲的divergeNode
divergeInfo = mDeadPool.get(0);
mDeadPool.remove(0);
}
if (divergeInfo == null) {
divergeInfo = createDivergeNode(mQueen.get(0));
}
divergeInfo.reset();
divergeInfo.mType = mQueen.get(0);
mDivergeInfos.add(divergeInfo);
mQueen.remove(0);
}
在dealDiverge里面计算已经在走动画的爱心的位置
for (int i = 0; i < mDivergeInfos.size(); i++) {
DivergeInfo divergeInfo = mDivergeInfos.get(i);
float timeLeft = 1.0F - divergeInfo.mDuration;
divergeInfo.mDuration += mDuration;
float x, y;
//二次贝塞尔
float time1 = timeLeft * timeLeft;
float time2 = 2 * timeLeft * divergeInfo.mDuration;
float time3 = divergeInfo.mDuration * divergeInfo.mDuration;
x = time1 * (mPtStart.x)
+ time2 * (divergeInfo.mBreakPoint.x)
+ time3 * (divergeInfo.mEndPoint.x);
divergeInfo.mX = x;
y = time1 * (mPtStart.y)
+ time2 * (divergeInfo.mBreakPoint.y)
+ time3 * (divergeInfo.mEndPoint.y);
divergeInfo.mY = y;
if (divergeInfo.mY <= divergeInfo.mEndPoint.y) {
mDivergeInfos.remove(i);
mDeadPool.add(divergeInfo);
i--;
continue;
}
}
onDraw方法
for (DivergeInfo divergeInfo : mDivergeInfos) {
mPaint.setAlpha((int) (255 * divergeInfo.mY / mPtStart.y));
Bitmap bm = mDivergeViewProvider.getBitmap(divergeInfo.mType);
float originCenterX = divergeInfo.mX + bm.getWidth() / 2;
float originCenterY = divergeInfo.mY + bm.getHeight() / 2;
float scaleWidth, scaleHeight;
scaleWidth = bm.getWidth();
scaleHeight = bm.getHeight();
RectF destRect = new RectF(originCenterX - scaleWidth / 2, originCenterY - scaleHeight / 2,
originCenterX + scaleWidth / 2, originCenterY + scaleHeight / 2);
canvas.drawBitmap(bm, null
, destRect,
mPaint);
}
mIsDrawing = false;
ps:映客的点赞爱心就是这么实现的(映客是本地点赞出爱心,这个直接分析元素会失败,可以进入直播后,断网然后分析元素)
2.1. 优化方向:
- 停止爱心动画的时机(什么时候可以停止while循环)
- 削峰:Android 每隔 16.6 ms 刷新一次屏幕,可以根据这个计算一次主流机型阈值
都需要利用到削峰
额外知识点
二阶贝塞尔曲线公式:
三阶贝塞尔曲线公式: