天天看點

仿美團外賣底部導航欄動畫

體驗了一下美團外賣的底部導航欄,感覺動畫很流暢,分割線被頂起,還有圖示的動畫,可能用的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()中畫上圖檔也用屬性動畫移動就成功啦。

因為有曲線銜接貝塞爾曲線,不同曲線銜接處的過度在寬屏機器上不是很流暢,有更好的方法歡迎補充!!!

下載下傳位址哦!!!!

資源下載下傳位址