Android实现笑脸进度加载动画

最近看到豆瓣的笑脸loading很有意思,看一张效果图:

下面分析一下如何实现这样的效果:

1、默认状态是一张笑脸的状态(一个嘴巴,两个眼睛,默认状态)

2、开始旋转,嘴巴追上眼睛(合并状态)

3、追上以后自转一周(自转状态)

4、然后逐渐释放眼睛(分离状态)

5、回到初始笑脸状态(默认状态)

一、默认状态

首先需要确定好嘴巴和眼睛的初始位置,我这里的初始化嘴巴是一个半圆,在横轴下方。眼睛分别与横轴夹角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() {
        //默认两个眼睛坐标位置 角度转弧度
        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));
    }

注意:需要将角度转弧度

(2)开始画眼睛

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

二、合并状态

这个状态可以分为两部分

  • 嘴巴的旋转
  • 眼睛的旋转

1、嘴巴的旋转

开启动画

     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) {
                //恢复起始状态
                currentStatus = smileStatus;
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

动画执行时间1s,记录动画当前执行进度值,存放在faceValue中。当动画执行结束的时候,需要将状态恢复到默认状态,调用invalidate的时候,进入onDraw()方法,开始重新绘制嘴巴。

                //记录时刻的旋转角度
                startAngle = faceValue * 360;

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

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

                    //开始自转一圈
                    mHandler.sendEmptyMessage(2);

                    //此时记录自转一圈起始的角度
                    circleStartAngle = 120 + startAngle / 2;

                } else {

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

                }

这里的每次旋转角度为startAngle。当完全追赶上右侧眼睛的时候,开始执行自转一周,并停止当前动画。

2、眼睛的旋转

眼睛的开始旋转速度明显是慢于嘴巴的旋转速度,所以每次的旋转速度可以设置为嘴巴的一半

  //画左边眼睛 ,旋转的角度设置为笑脸旋转角度的一半,这样笑脸才能追上眼睛
  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);

  //画右边眼睛 ,旋转的角度设置为笑脸旋转角度的一半,这样笑脸才能追上眼睛
  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);

三、自转状态

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);

四、分离状态

主要的注意点就是眼睛的旋转角度设置为嘴巴旋转角度的2倍,这样才会达到眼睛超过嘴巴的效果,主要的旋转代码如下:

                startAngle = faceValue * 360;
                //判断当前笑脸的起点是否已经走过260度 (吐出眼睛的角度,角度可以任意设置)
                if (startAngle >= splitAngle) {

                    //画左边眼睛 ,旋转的角度设置为笑脸旋转角度的2倍,这样眼睛才能快于笑脸旋转速度
                    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);

                    //画右边眼睛 ,旋转的角度设置为笑脸旋转角度的2倍,这样眼睛才能快于笑脸旋转速度
                    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;

    //笑脸状态(一个脸,两个眼睛)
    private final int smileStatus = 0;

    //加载状态 合并眼睛,旋转
    private final int loadingStatus = 1;

    //合并完成 转一圈
    private final int circleStatus = 2;

    //转圈完成 吐出眼睛
    private final int splitStatus = 3;

    //当前状态
    private int currentStatus = smileStatus;

    //笑脸画笔
    private Paint facePaint;
    //眼睛画笔
    private Paint eyePaint;

    //笑脸开始角度
    private float startAngle;
    //笑脸弧度
    private float swipeAngle;

    //左侧眼睛起点x轴坐标
    private float leftEyeX = 0;
    //左侧眼睛起点y轴坐标
    private float leftEyeY = 0;

    //右侧眼睛起点x轴坐标
    private float rightEyeX;
    //右侧眼睛起点y轴坐标
    private float rightEyeY;

    //一开始默认状态笑脸转圈动画
    private ValueAnimator faceLoadingAnimator;

    //吞并完成后,自转一圈动画
    private ValueAnimator circleAnimator;

    //faceLoadingAnimator动画进度值
    private float faceValue;

    //circleAnimator动画进度值
    private float circleValue;

    //记录开始自转一圈的起始角度
    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() {
        //默认两个眼睛坐标位置 角度转弧度
        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:
                    //启动一开始笑脸转圈动画,并且开始合并眼睛
                    currentStatus = loadingStatus;
                    faceLoadingAnimator.start();
                    break;

                case 2:
                    //暂停眼睛和笑脸动画
                    currentStatus = circleStatus;
                    faceLoadingAnimator.pause();
                    //启动笑脸自转一圈动画
                    circleAnimator.start();
                    break;
                case 3:
                    //恢复笑脸转圈动画,并且开始分离眼睛
                    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) {
            //起始状态
            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);

                //更改状态,进行笑脸合并眼睛
                mHandler.sendEmptyMessage(1);
                break;

            //合并状态
            case loadingStatus:

                //记录时刻的旋转角度
                startAngle = faceValue * 360;

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

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

                    //开始自转一圈
                    mHandler.sendEmptyMessage(2);

                    //此时记录自转一圈起始的角度
                    circleStartAngle = 120 + startAngle / 2;

                } else {

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

                }

                //画左边眼睛 ,旋转的角度设置为笑脸旋转角度的一半,这样笑脸才能追上眼睛
                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);

                //画右边眼睛 ,旋转的角度设置为笑脸旋转角度的一半,这样笑脸才能追上眼睛
                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;

            //自转一圈状态 circleValue * 360 为旋转角度
            case circleStatus:
                canvas.drawArc(-radius, -radius, radius, radius,
                        circleStartAngle + circleValue * 360,
                        swipeAngle, false, facePaint);
                break;

            //笑脸眼睛分离状态
            case splitStatus:

                startAngle = faceValue * 360;
                //判断当前笑脸的起点是否已经走过260度 (吐出眼睛的角度,角度可以任意设置)
                if (startAngle >= splitAngle) {

                    //画左边眼睛 ,旋转的角度设置为笑脸旋转角度的2倍,这样眼睛才能快于笑脸旋转速度
                    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);

                    //画右边眼睛 ,旋转的角度设置为笑脸旋转角度的2倍,这样眼睛才能快于笑脸旋转速度
                    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) {
                //恢复起始状态
                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"/>

完整代码都在上面啦.

到这里就结束啦.

以上就是Android实现笑脸进度加载动画的详细内容,更多关于Android 笑脸进度加载的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android使用View Animation实现动画加载界面

    之前分别介绍了View Animation和Drawable Animation,学了就要用啊,今天给大家一个使用View Animation实现动画加载界面的实现. 首先先看一下实现效果. 下面是实现代码 package com.example.animationloading; import java.util.Timer; import java.util.TimerTask; import android.annotation.SuppressLint; import android.a

  • android自定义波浪加载动画的实现代码

    本文实例为大家分享了android自定义波浪加载动画的具体代码,供大家参考,具体内容如下 效果图 1.自定义控件 WaveView package com.example.wh.myapplication; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import andro

  • Android仿视频加载旋转小球动画效果的实例代码

    先上个效果图,以免大家跑错地了. 嗯,除了只能录三秒,其他没啥问题. 下面分析一下怎么实现上面这个效果. 理性分析后我们可以看到是几个小球绕着一个圆进行运动,那这里面的重点我们看看什么. 绘制五个球,没什么难度,让球绕圆进行运动,这个好像我们没有见到是怎么去实现了,那下就说这个. 从本质上看,球绕圆运动,其实我们可以看作是一个物体绕指定的路劲运动,那我们就有下面几个东西需要说一下: 1:Path 2:ValueAnimator 3:PathMeasure 前两个大家应该都见过,一个是路径,就是可

  • Android 自定义加载动画Dialog弹窗效果的示例代码

    效果图 首先是创建弹窗的背景 这是上面用到的 以shape_bg_5_blue.xml为例,其他的三个无非就是里面的颜色不一样而已 <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="5dp"

  • Android自定义加载圈动画效果

    本文实例为大家分享了Android自定义加载圈动画展示的具体代码,供大家参考,具体内容如下 实现如下效果: 该效果图主要有3个动画: 1.旋转动画 2.聚合动画 3.扩散动画 以上3个动画都是通过ValueAnimator来实现,配合自定义View的onDraw()方法实现不断的刷新和绘制界面. 具体代码如下: package blog.csdn.net.mchenys.myanimationloading; import android.animation.Animator; import a

  • Android实现仿微软系统加载动画效果

    效果图: 实现步骤: 初始化五个圆球分别设置中心点,方便画圆 利用ValueAnimator的值变化来获取旋转角度 onDraw来分别画每个圆 具体代码实现: 1.创建Circle对象 package com.sjl.keeplive.track; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PointF; public class Circle { private

  • android实现加载动画对话框

    本文实例为大家分享了android实现加载动画对话框的具体代码,供大家参考,具体内容如下 先来两张效果图 自定义对话框: public class LoadingProgressDialog extends ProgressDialog { private AnimationDrawable mAnimation; private Context mContext; private ImageView mImageView; private String mLoadingTitle; priva

  • Android使用lottie加载json动画的示例代码

    Lottie Lottie是 Airbnb 开源的一个动画项目,它支持 iOS, mac OS Android RN,由于某些复杂动画的实现,往往会写很多的 code 来实现它,而且调试动画的效果会比较花费时间.用它来解决某些动画会带来很大的便利. 设计师在After Effects设计好相关的动画,然后安装上BodyMovin这个插件,这个插件,可以帮导出动画效果的 JSON 文件,然后我们可以通过 Lottie 来加载相关的 JSON 文件来实现动画效果. 优势 开发可以方便的实现动画,节约

  • Android 使用 Path 实现搜索动态加载动画效果

    今天实现一个搜索动态加载数据的动画效果,还是先看效果吧,用文字描述干巴巴的,看图说话什么都明白了, 实现这个就是使用Path中的getSegment()不断的去改变它截取片段的start和stop,再结合动画,今天就分步骤实现它,看完以后你也会觉的不是很难,只是没想到这么实现而已,所以要多见识,所谓眼界决定你的高度,还是延续我写博客的习惯,一步步分析,第一步就是绘制如下图: 如果单纯的绘制这个图很简单很简单的,绘制一个圆,然后再绘制一根线就搞定,但是要考虑这里的效果,就不能这么干了,如果你看了上

  • Android实现笑脸进度加载动画

    最近看到豆瓣的笑脸loading很有意思,看一张效果图: 下面分析一下如何实现这样的效果: 1.默认状态是一张笑脸的状态(一个嘴巴,两个眼睛,默认状态) 2.开始旋转,嘴巴追上眼睛(合并状态) 3.追上以后自转一周(自转状态) 4.然后逐渐释放眼睛(分离状态) 5.回到初始笑脸状态(默认状态) 一.默认状态 首先需要确定好嘴巴和眼睛的初始位置,我这里的初始化嘴巴是一个半圆,在横轴下方.眼睛分别与横轴夹角60度,如下图: 这两部分可以使用pathMeasure,我这里使用最简单的两个api:can

  • Android仿支付宝笑脸刷新加载动画的实现代码

    看到支付宝的下拉刷新有一个笑脸的动画,因此自己也动手实现一下.效果图如下: 一.总体思路 1.静态部分的笑脸. 这一部分的笑脸就是一个半圆弧,加上两颗眼睛,这部分比较简单,用于一开始的展示. 2.动态笑脸的实现. 2.1.先是从底部有一个圆形在运动,运动在左眼位置时把左眼给绘制,同时圆形继续运动,运动到右眼位置时绘制右眼,圆形继续运动到最右边的位置. 2.2.当上面的圆形运动到最右边时候,开始不断绘制脸,从右向左,脸不断增长,这里脸设置为接近半个圆形的大小. 2.3.当脸画完的时候,开始让脸旋转

  • 原生JS实现首页进度加载动画

    js进度加载动画程序是本人的个人作品,写的不好,可以参考,但未经本人允许,请不要用于其它用途! 早上写了个首页进度加载动画,本想在我的博客里用上,测试发现博客园加载太快,根本看不到动画效果,直接就加载'Complete'了,算了,还是不要把博客搞得太臃肿了! 于是我就写了个演示页面,在body里加了个iframe来加载大一点的网站,这样就看出效果了! 用Safari打开貌似CSS动画的播放时间变成同步了,不知道什么原因,本地测试又没问题(请大神指点!),用Chrome.Firefox倒是没问题,

  • Android开发之自定义加载动画详解

    目录 一.demo简介 二.分析贪吃动画的尺寸比例 三.画圆 四.实现张嘴闭嘴动画 五.小球移动动画 一.demo简介 1.效果展示如下图,我截了三个瞬间,但其实这是一个连续的动画,就是这个大圆不停地吞下小圆. 2.这个动画可以拆分为两部分,首先是大圆张嘴闭嘴的动画,相当于画一个圆弧,规定一下它的角度就好.小圆就是一个从右向左移动的动画.然后不停地刷新界面,让动画的持续时间为永恒,这样就会有一个持续的动态效果. 二.分析贪吃动画的尺寸比例 1.在制作动画之前,我们要先建一个模型,来确定一下大圆和

  • Android仿网易一元夺宝客户端下拉加载动画效果(一)

    上上周写的一个demo,仿照网易一元夺宝的下拉刷新效果. 原效果是(第一部分)一个小太阳拉下来,然后松开回弹上去, (第二部分)再掉下来一个硬币进行中轴旋转. 本文实现的效果的是第一部分的,效果演示图如下: Gif图看起来比较卡顿...其实真机演示效果还是很流畅的. 下面分析实现过程: 当时因为时间有限没有写在下拉刷新的组件中,也没有封装成一个单独的组件,只是在主布局后面写了一个View然后实现相应的操作,进行封装并不难,这里就不花时间BB了,下面是布局文件: <RelativeLayout x

  • Android实现简单的加载进度条

    本文实例为大家分享了Android实现简单的加载进度条的具体代码,供大家参考,具体内容如下 1.效果图 2.自定义progressBar package com.example.myapplication7; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; im

  • 分享8款优秀的 jQuery 加载动画和进度条插件

    加载动画和进度条在网站和 Web 应用中的使用非常流行.虽然网速越来越快,但是我们的网站越来越复杂,同时用户对网站的使用体验的要求也越来越高.在内容加载缓慢的时候,使用时尚的加载动画和进度条告诉用户还有内容正在加载是一种非常好的方式.今天这篇文章向大家推荐10款基于 jQuery 实现的加载动画和进度条插件. Spin.js 最喜欢这款插件了,动画图片的长度.粗细.速度和角度都可以灵活控制,想要做成什么样都可以. 源码下载    在线演示 Percentage Loader 一款轻量的 jQue

  • Android自定义view实现阻尼效果的加载动画

    效果: 需要知识: 1. 二次贝塞尔曲线 2. 动画知识 3. 基础自定义view知识 先来解释下什么叫阻尼运动 阻尼振动是指,由于振动系统受到摩擦和介质阻力或其他能耗而使振幅随时间逐渐衰减的振动,又称减幅振动.衰减振动.[1] 不论是弹簧振子还是单摆由于外界的摩擦和介质阻力总是存在,在振动过程中要不断克服外界阻力做功,消耗能量,振幅就会逐渐减小,经过一段时间,振动就会完全停下来.这种振幅随时间减小的振动称为阻尼振动.因为振幅与振动的能量有关,阻尼振动也就是能量不断减少的振动.阻尼振动是非简谐运

  • Android自定义加载控件实现数据加载动画

    本文实例为大家分享了Android自定义加载控件,第一次小人跑动的加载效果眼前一亮,相比传统的PrograssBar高大上不止一点,于是走起,自定义了控件LoadingView去实现动态效果,可直接在xml中使用,具体实现如下 package com.*****.*****.widget; import android.content.Context; import android.graphics.drawable.AnimationDrawable; import android.util.

  • android仿爱奇艺加载动画实例

    本篇文章介绍了android仿爱奇艺加载动画实例,具体代码如下: 效果图: 用到的知识点: Path ValueAnimator 如果对Path和ValueAnimator还不熟悉推荐去看这几个大神的Blog自定义view的目前讲的最适合我的文章 ,自定义view的详细教程和实践,这个也是教程和实践,感谢他们的付出!(希望大家可以认真看完,可以得到很多启发). 拆解动画 一个圆先顺时针的慢慢画出来(圆不是一个闭合的圆) 这一步是一个组合动画,圆慢慢的消失,同时三角形顺时针旋转 这里的难点主要就是

随机推荐