欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實現(xiàn)笑臉進度加載動畫

 更新時間:2021年05月06日 09:32:51   作者:qinbin2015  
這篇文章主要介紹了Android實現(xiàn)笑臉進度加載動畫的方法,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下

最近看到豆瓣的笑臉loading很有意思,看一張效果圖:

下面分析一下如何實現(xiàn)這樣的效果:

1、默認狀態(tài)是一張笑臉的狀態(tài)(一個嘴巴,兩個眼睛,默認狀態(tài))

2、開始旋轉(zhuǎn),嘴巴追上眼睛(合并狀態(tài))

3、追上以后自轉(zhuǎn)一周(自轉(zhuǎn)狀態(tài))

4、然后逐漸釋放眼睛(分離狀態(tài))

5、回到初始笑臉狀態(tài)(默認狀態(tài))

一、默認狀態(tài)

首先需要確定好嘴巴和眼睛的初始位置,我這里的初始化嘴巴是一個半圓,在橫軸下方。眼睛分別與橫軸夾角60度,如下圖:

這兩部分可以使用pathMeasure,我這里使用最簡單的兩個api:canvas.drawArc()和canvas.drawPoint()。

1、畫嘴巴

 //畫起始笑臉
canvas.drawArc(-radius, -radius, radius, radius, startAngle, swipeAngle, false,facePaint);

這里的startAngle初始值為0,swiperAngle為180,半徑radius為40。

2、畫眼睛

(1)初始化眼睛坐標

   /**
     * 初始化眼睛坐標
     */
    private void initEyes() {
        //默認兩個眼睛坐標位置 角度轉(zhuǎn)弧度
        leftEyeX = (float) (-radius * Math.cos(eyeStartAngle * Math.PI / 180));
        leftEyeY = (float) (-radius * Math.sin(eyeStartAngle * Math.PI / 180));
        rightEyeX = (float) (radius * Math.cos(eyeStartAngle * Math.PI / 180));
        rightEyeY = (float) (-radius * Math.sin(eyeStartAngle * Math.PI / 180));
    }

注意:需要將角度轉(zhuǎn)弧度

(2)開始畫眼睛

   //畫起始眼睛
  canvas.drawPoint(leftEyeX, leftEyeY, eyePaint);
  canvas.drawPoint(rightEyeX, rightEyeY, eyePaint);

二、合并狀態(tài)

這個狀態(tài)可以分為兩部分

  • 嘴巴的旋轉(zhuǎn)
  • 眼睛的旋轉(zhuǎn)

1、嘴巴的旋轉(zhuǎn)

開啟動畫

     faceLoadingAnimator = ValueAnimator.ofFloat(0, 1).setDuration(1000);
     faceLoadingAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
     faceLoadingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                faceValue = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        //動畫延遲500ms啟動
        faceLoadingAnimator.setStartDelay(200);

        faceLoadingAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                //恢復(fù)起始狀態(tài)
                currentStatus = smileStatus;
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

動畫執(zhí)行時間1s,記錄動畫當(dāng)前執(zhí)行進度值,存放在faceValue中。當(dāng)動畫執(zhí)行結(jié)束的時候,需要將狀態(tài)恢復(fù)到默認狀態(tài),調(diào)用invalidate的時候,進入onDraw()方法,開始重新繪制嘴巴。

                //記錄時刻的旋轉(zhuǎn)角度
                startAngle = faceValue * 360;


                //追上右邊眼睛
                if (startAngle >= 120 + startAngle / 2) {

                    canvas.drawArc(-radius, -radius, radius, radius, startAngle,
                            swipeAngle, false, facePaint);

                    //開始自轉(zhuǎn)一圈
                    mHandler.sendEmptyMessage(2);

                    //此時記錄自轉(zhuǎn)一圈起始的角度
                    circleStartAngle = 120 + startAngle / 2;

                } else {

                    //追眼睛的過程
                    canvas.drawArc(-radius, -radius, radius, radius, startAngle,
                            swipeAngle, false, facePaint);

                }

這里的每次旋轉(zhuǎn)角度為startAngle。當(dāng)完全追趕上右側(cè)眼睛的時候,開始執(zhí)行自轉(zhuǎn)一周,并停止當(dāng)前動畫。

2、眼睛的旋轉(zhuǎn)

眼睛的開始旋轉(zhuǎn)速度明顯是慢于嘴巴的旋轉(zhuǎn)速度,所以每次的旋轉(zhuǎn)速度可以設(shè)置為嘴巴的一半

  //畫左邊眼睛 ,旋轉(zhuǎn)的角度設(shè)置為笑臉旋轉(zhuǎn)角度的一半,這樣笑臉才能追上眼睛
  leftEyeX = (float) (-radius * Math.cos((60 + startAngle / 2) * Math.PI / 180));
  leftEyeY = (float) (-radius * Math.sin((60 + startAngle / 2) * Math.PI / 180));
  canvas.drawPoint(leftEyeX, leftEyeY, eyePaint);

  //畫右邊眼睛 ,旋轉(zhuǎn)的角度設(shè)置為笑臉旋轉(zhuǎn)角度的一半,這樣笑臉才能追上眼睛
  rightEyeX = (float) (radius * Math.cos((60 - startAngle / 2) * Math.PI / 180));
  rightEyeY = (float) (-radius * Math.sin((60 - startAngle / 2) * Math.PI / 180));
  canvas.drawPoint(rightEyeX, rightEyeY, eyePaint);

三、自轉(zhuǎn)狀態(tài)

1、開啟動畫

        circleAnimator = ValueAnimator.ofFloat(0, 1).setDuration(1000);

        circleAnimator.setInterpolator(new LinearInterpolator());

        circleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                circleValue = (float) animation.getAnimatedValue();
                invalidate();
            }
        });

        circleAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mHandler.sendEmptyMessage(3);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

2、重新繪制

 canvas.drawArc(-radius, -radius, radius, radius,
                        circleStartAngle + circleValue * 360,
                        swipeAngle, false, facePaint);

四、分離狀態(tài)

主要的注意點就是眼睛的旋轉(zhuǎn)角度設(shè)置為嘴巴旋轉(zhuǎn)角度的2倍,這樣才會達到眼睛超過嘴巴的效果,主要的旋轉(zhuǎn)代碼如下:

                startAngle = faceValue * 360;
                //判斷當(dāng)前笑臉的起點是否已經(jīng)走過260度 (吐出眼睛的角度,角度可以任意設(shè)置)
                if (startAngle >= splitAngle) {

                    //畫左邊眼睛 ,旋轉(zhuǎn)的角度設(shè)置為笑臉旋轉(zhuǎn)角度的2倍,這樣眼睛才能快于笑臉旋轉(zhuǎn)速度
                    leftEyeX = (float) (-radius * Math.cos((eyeStartAngle + startAngle * 2) * Math.PI / 180));
                    leftEyeY = (float) (-radius * Math.sin((eyeStartAngle + startAngle * 2) * Math.PI / 180));
                    canvas.drawPoint(leftEyeX, leftEyeY, eyePaint);

                    //畫右邊眼睛 ,旋轉(zhuǎn)的角度設(shè)置為笑臉旋轉(zhuǎn)角度的2倍,這樣眼睛才能快于笑臉旋轉(zhuǎn)速度
                    rightEyeX = (float) (radius * Math.cos((eyeStartAngle - startAngle * 2) * Math.PI / 180));
                    rightEyeY = (float) (-radius * Math.sin((eyeStartAngle - startAngle * 2) * Math.PI / 180));
                    canvas.drawPoint(rightEyeX, rightEyeY, eyePaint);

                }
                //畫笑臉
                canvas.drawArc(-radius, -radius, radius, radius, startAngle, swipeAngle,
                        false, facePaint);

最后附上完整代碼

public class FaceView2 extends View {


    //圓弧半徑
    private int radius = 40;

    //圓弧畫筆寬度
    private float paintWidth = 15;

    //笑臉狀態(tài)(一個臉,兩個眼睛)
    private final int smileStatus = 0;

    //加載狀態(tài) 合并眼睛,旋轉(zhuǎn)
    private final int loadingStatus = 1;

    //合并完成 轉(zhuǎn)一圈
    private final int circleStatus = 2;

    //轉(zhuǎn)圈完成 吐出眼睛
    private final int splitStatus = 3;

    //當(dāng)前狀態(tài)
    private int currentStatus = smileStatus;

    //笑臉畫筆
    private Paint facePaint;
    //眼睛畫筆
    private Paint eyePaint;

    //笑臉開始角度
    private float startAngle;
    //笑臉弧度
    private float swipeAngle;

    //左側(cè)眼睛起點x軸坐標
    private float leftEyeX = 0;
    //左側(cè)眼睛起點y軸坐標
    private float leftEyeY = 0;

    //右側(cè)眼睛起點x軸坐標
    private float rightEyeX;
    //右側(cè)眼睛起點y軸坐標
    private float rightEyeY;

    //一開始默認狀態(tài)笑臉轉(zhuǎn)圈動畫
    private ValueAnimator faceLoadingAnimator;

    //吞并完成后,自轉(zhuǎn)一圈動畫
    private ValueAnimator circleAnimator;

    //faceLoadingAnimator動畫進度值
    private float faceValue;

    //circleAnimator動畫進度值
    private float circleValue;

    //記錄開始自轉(zhuǎn)一圈的起始角度
    private float circleStartAngle;

    //吐出眼睛的角度
    private float splitAngle;

    private float initStartAngle;

    //眼睛起始角度
    private float eyeStartAngle = 60;

    public FaceView2(Context context) {
        this(context, null);
    }

    public FaceView2(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FaceView2(Context context, AttributeSet attrs,
                     int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //自定義屬性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FaceView2,
                defStyleAttr, 0);

        initStartAngle = typedArray.getFloat(R.styleable.FaceView2_startAngle, 0);
        swipeAngle = typedArray.getFloat(R.styleable.FaceView2_swipeAngle, 180);
        splitAngle = typedArray.getFloat(R.styleable.FaceView2_splitAngle, 260);

        typedArray.recycle();

        startAngle = initStartAngle;
        eyeStartAngle += startAngle;

        initEyes();

        initPaint();

        //開始默認動畫
        initAnimator();

    }

    /**
     * 初始化畫筆
     */
    private void initPaint() {
        //初始化畫筆
        facePaint = new Paint();
        facePaint.setStrokeWidth(paintWidth);
        facePaint.setColor(Color.RED);
        facePaint.setAntiAlias(true);
        facePaint.setStyle(Paint.Style.STROKE);
        facePaint.setStrokeCap(Paint.Cap.ROUND);

        eyePaint = new Paint();
        eyePaint.setStrokeWidth(paintWidth);
        eyePaint.setColor(Color.RED);
        eyePaint.setAntiAlias(true);
        eyePaint.setStyle(Paint.Style.STROKE);
        eyePaint.setStrokeCap(Paint.Cap.ROUND);

    }

    /**
     * 初始化眼睛坐標
     */
    private void initEyes() {
        //默認兩個眼睛坐標位置 角度轉(zhuǎn)弧度
        leftEyeX = (float) (-radius * Math.cos(eyeStartAngle * Math.PI / 180));
        leftEyeY = (float) (-radius * Math.sin(eyeStartAngle * Math.PI / 180));
        rightEyeX = (float) (radius * Math.cos(eyeStartAngle * Math.PI / 180));
        rightEyeY = (float) (-radius * Math.sin(eyeStartAngle * Math.PI / 180));

    }

    private Handler mHandler = new Handler(new Handler.Callback() {
        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    //啟動一開始笑臉轉(zhuǎn)圈動畫,并且開始合并眼睛
                    currentStatus = loadingStatus;
                    faceLoadingAnimator.start();
                    break;

                case 2:
                    //暫停眼睛和笑臉動畫
                    currentStatus = circleStatus;
                    faceLoadingAnimator.pause();
                    //啟動笑臉自轉(zhuǎn)一圈動畫
                    circleAnimator.start();
                    break;
                case 3:
                    //恢復(fù)笑臉轉(zhuǎn)圈動畫,并且開始分離眼睛
                    currentStatus = splitStatus;
                    circleAnimator.cancel();
                    faceLoadingAnimator.resume();
                    invalidate();

                    break;
            }
            return false;
        }
    });

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //畫布移到中間
        canvas.translate(getWidth() / 2, getHeight() / 2);

        switch (currentStatus) {
            //起始狀態(tài)
            case smileStatus:
                //起始角度為0
                startAngle = initStartAngle;

                //畫起始笑臉
                canvas.drawArc(-radius, -radius, radius, radius, startAngle, swipeAngle, false,
                        facePaint);

                //重置起始眼睛坐標
                initEyes();

                //畫起始眼睛
                canvas.drawPoint(leftEyeX, leftEyeY, eyePaint);
                canvas.drawPoint(rightEyeX, rightEyeY, eyePaint);

                //更改狀態(tài),進行笑臉合并眼睛
                mHandler.sendEmptyMessage(1);
                break;

            //合并狀態(tài)
            case loadingStatus:

                //記錄時刻的旋轉(zhuǎn)角度
                startAngle = faceValue * 360;


                //追上右邊眼睛
                if (startAngle >= 120 + startAngle / 2) {

                    canvas.drawArc(-radius, -radius, radius, radius, startAngle,
                            swipeAngle, false, facePaint);

                    //開始自轉(zhuǎn)一圈
                    mHandler.sendEmptyMessage(2);

                    //此時記錄自轉(zhuǎn)一圈起始的角度
                    circleStartAngle = 120 + startAngle / 2;

                } else {

                    //追眼睛的過程
                    canvas.drawArc(-radius, -radius, radius, radius, startAngle,
                            swipeAngle, false, facePaint);

                }

                //畫左邊眼睛 ,旋轉(zhuǎn)的角度設(shè)置為笑臉旋轉(zhuǎn)角度的一半,這樣笑臉才能追上眼睛
                leftEyeX = (float) (-radius * Math.cos((60 + startAngle / 2) * Math.PI / 180));
                leftEyeY = (float) (-radius * Math.sin((60 + startAngle / 2) * Math.PI / 180));
                canvas.drawPoint(leftEyeX, leftEyeY, eyePaint);

                //畫右邊眼睛 ,旋轉(zhuǎn)的角度設(shè)置為笑臉旋轉(zhuǎn)角度的一半,這樣笑臉才能追上眼睛
                rightEyeX = (float) (radius * Math.cos((60 - startAngle / 2) * Math.PI / 180));
                rightEyeY = (float) (-radius * Math.sin((60 - startAngle / 2) * Math.PI / 180));
                canvas.drawPoint(rightEyeX, rightEyeY, eyePaint);
                break;

            //自轉(zhuǎn)一圈狀態(tài) circleValue * 360 為旋轉(zhuǎn)角度
            case circleStatus:
                canvas.drawArc(-radius, -radius, radius, radius,
                        circleStartAngle + circleValue * 360,
                        swipeAngle, false, facePaint);
                break;

            //笑臉眼睛分離狀態(tài)
            case splitStatus:

                startAngle = faceValue * 360;
                //判斷當(dāng)前笑臉的起點是否已經(jīng)走過260度 (吐出眼睛的角度,角度可以任意設(shè)置)
                if (startAngle >= splitAngle) {

                    //畫左邊眼睛 ,旋轉(zhuǎn)的角度設(shè)置為笑臉旋轉(zhuǎn)角度的2倍,這樣眼睛才能快于笑臉旋轉(zhuǎn)速度
                    leftEyeX = (float) (-radius * Math.cos((eyeStartAngle + startAngle * 2) * Math.PI / 180));
                    leftEyeY = (float) (-radius * Math.sin((eyeStartAngle + startAngle * 2) * Math.PI / 180));
                    canvas.drawPoint(leftEyeX, leftEyeY, eyePaint);

                    //畫右邊眼睛 ,旋轉(zhuǎn)的角度設(shè)置為笑臉旋轉(zhuǎn)角度的2倍,這樣眼睛才能快于笑臉旋轉(zhuǎn)速度
                    rightEyeX = (float) (radius * Math.cos((eyeStartAngle - startAngle * 2) * Math.PI / 180));
                    rightEyeY = (float) (-radius * Math.sin((eyeStartAngle - startAngle * 2) * Math.PI / 180));
                    canvas.drawPoint(rightEyeX, rightEyeY, eyePaint);

                }
                //畫笑臉
                canvas.drawArc(-radius, -radius, radius, radius, startAngle, swipeAngle,
                        false, facePaint);

                break;

        }
    }

    /**
     * 初始化動畫
     */
    private void initAnimator() {


        faceLoadingAnimator = ValueAnimator.ofFloat(0, 1).setDuration(1000);
        faceLoadingAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        faceLoadingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                faceValue = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        //動畫延遲500ms啟動
        faceLoadingAnimator.setStartDelay(200);

        faceLoadingAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                //恢復(fù)起始狀態(tài)
                currentStatus = smileStatus;
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });


        circleAnimator = ValueAnimator.ofFloat(0, 1).setDuration(1000);

        circleAnimator.setInterpolator(new LinearInterpolator());

        circleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                circleValue = (float) animation.getAnimatedValue();
                invalidate();
            }
        });

        circleAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mHandler.sendEmptyMessage(3);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
    }
}

自定義屬性

<declare-styleable name="FaceView2">
        <attr name="startAngle" format="dimension" />
        <attr name="swipeAngle" format="dimension" />
        <attr name="splitAngle" format="dimension" />
</declare-styleable>

布局文件中使用

<com.example.viewdemo.FaceView2
     android:layout_width="match_parent"
     android:layout_height="match_parent"/>

完整代碼都在上面啦.

到這里就結(jié)束啦.

以上就是Android實現(xiàn)笑臉進度加載動畫的詳細內(nèi)容,更多關(guān)于Android 笑臉進度加載的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論