点赞爱心动画

场景

实现直播房间点赞爱心动画(不是送礼物的动画)
难点:流畅的飘爱心

1. 方案1

直接使用animator做动画
参考资料: https://github.com/Yasic/QQBubbleView

1.1. 优化方向:

  1. 削峰
  2. 不要每次都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. 优化方向:

  1. 停止爱心动画的时机(什么时候可以停止while循环)
  2. 削峰:Android 每隔 16.6 ms 刷新一次屏幕,可以根据这个计算一次主流机型阈值

都需要利用到削峰

额外知识点

二阶贝塞尔曲线公式:
二阶

三阶贝塞尔曲线公式:
三阶

在线演示:http://myst729.github.io/bezier-curve/