體驗了一下美團外賣的底部導航欄,感覺動畫很流暢,分割線被頂起,還有圖標的動畫,可能用的lottie,覺得分割線被頂起可以自己寫動畫,所以試着寫了一下 。
想自定義view點擊實現動畫效果,自定義view的區域一定比背景需要被頂起的線要高,所以佈局如下:
開始繪製view,被頂起的曲線分三段,前後兩端曲線對稱的,用path繪製曲線,中間段繪製貝塞爾曲線。
那麼我們分別繪製三段曲線,用ValueAnimator實現效果,
private void initAnim() {
value = startValue;
animator = ValueAnimator.ofInt(startValue, halfValue, endValue);
// animator.setInterpolator(new DecelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
value = (int) valueAnimator.getAnimatedValue();
invalidate();
}
});
animator.setDuration(ANIM_TIME);
animator.start();
}
動畫執行過程中有個回彈,那麼value的變化需要一箇中間值,
startValue = 0;
halfValue = -DensityUtils.dp2px(context, 35);
endValue = -DensityUtils.dp2px(context, 25);
在onDraw中繪製曲線代碼如下,
rectF = new RectF((((float)width - (float)contentSize) / 2),
lineToTop + value,
(float) width - ((float)width - (float)contentSize) / 2,
height + value);
if (value < 0 ) {
Path path = new Path();
//繪製第一段圓弧
path.moveTo(rectF.left - 20, lineToTop);
float firstCubicHight = ((float) lineToTop - rectF.top) / 4;
float end = (float) lineToTop - firstCubicHight;
path.cubicTo(
rectF.left - 10,
(float) lineToTop - firstCubicHight / 16,
rectF.left,
(float) lineToTop - firstCubicHight / 12,
rectF.left + 10,
end
);
//繪製第二段圓弧
path.quadTo(
rectF.left + contentSize / 2,
rectF.top * 0.9f,
rectF.right - 10,
end
);
//繪製第三段圓弧,和第一段對稱
path.cubicTo(
rectF.right,
(float) lineToTop - firstCubicHight / 12,
rectF.right + 10,
(float) lineToTop - firstCubicHight / 16,
rectF.right + 20,
lineToTop
);
Path pathBg = new Path();
pathBg.addPath(path);
pathBg.lineTo(rectF.right + 20, height);
pathBg.lineTo(rectF.left - 20, height);
pathBg.lineTo(rectF.left - 20, lineToTop);
canvas.drawPath(pathBg, paintBg);//繪製白色背景
canvas.drawPath(path, paintBgStroke);//繪製曲線
}
最後在onDraw()中畫上圖片也用屬性動畫移動就成功啦。
因爲有曲線銜接貝塞爾曲線,不同曲線銜接處的過度在寬屏機器上不是很流暢,有更好的方法歡迎補充!!!
下載地址哦!!!!