欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android实现跳动的小球加载动画效果

程序员文章站 2024-03-06 20:23:56
先来看看效果图 跳动的小球做这个动画,需掌握:      1、属性动画    &nb...

先来看看效果图

Android实现跳动的小球加载动画效果

跳动的小球做这个动画,需掌握:

     1、属性动画

     2、path类、canvas类

     3、贝塞尔曲线

     4、surfaceview用法

     5、自定义attr属性

     6 、架构: 状态模式,控制器

     7 、*落体,抛物线等概念

不多说了,直接上码

1.dancingview.java

public class dancingview extends surfaceview implements surfaceholder.callback {

  public static final int state_down = 1;//向下状态
  public static final int state_up = 2;//向上状态

  public static final int default_point_radius = 10;
  public static final int default_ball_radius = 13;
  public static final int default_line_width = 200;
  public static final int default_line_height = 2;
  public static final int default_line_color = color.parsecolor("#ff9800");
  public static final int default_point_color = color.parsecolor("#9c27b0");
  public static final int default_ball_color = color.parsecolor("#ff4081");

  public static final int default_down_duration = 600;//ms
  public static final int default_up_duration = 600;//ms
  public static final int default_freedown_duration = 1000;//ms

  public static final int max_offset_y = 50;//水平下降最大偏移距离


  public int ponit_radius = default_point_radius;//小球半径
  public int ball_radius = default_ball_radius;//小球半径

  private paint mpaint;
  private path mpath;
  private int mlinecolor;
  private int mponitcolor;
  private int mballcolor;
  private int mlinewidth;
  private int mlineheight;

  private float mdowndistance;
  private float mupdistance;
  private float freeballdistance;

  private valueanimator mdowncontroller;//下落控制器
  private valueanimator mupcontroller;//上弹控制器
  private valueanimator mfreedowncontroller;//*落体控制器

  private animatorset animatorset;
  private int state;

  private boolean ismupcontrollerdied = false;
  private boolean isanimationshowing = false;
  private boolean isbounced = false;
  private boolean isballfreeup = false;

  public dancingview(context context) {
    super(context);
    init(context, null);
  }

  public dancingview(context context, attributeset attrs) {
    super(context, attrs);
    init(context, attrs);
  }


  public dancingview(context context, attributeset attrs, int defstyleattr) {
    super(context, attrs, defstyleattr);
    init(context, attrs);
  }


  private void init(context context, attributeset attrs) {
    initattributes(context, attrs);

    mpaint = new paint();
    mpaint.setantialias(true);
    mpaint.setstrokewidth(mlineheight);
    mpaint.setstrokecap(paint.cap.round);

    mpath = new path();
    getholder().addcallback(this);

    initcontroller();
  }

  private void initattributes(context context, attributeset attrs) {
    typedarray typearray = context.obtainstyledattributes(attrs, r.styleable.dancingview);
    mlinecolor = typearray.getcolor(r.styleable.dancingview_linecolor, default_line_color);
    mlinewidth = typearray.getdimensionpixeloffset(r.styleable.dancingview_linewidth, default_line_width);
    mlineheight = typearray.getdimensionpixeloffset(r.styleable.dancingview_lineheight, default_line_height);
    mponitcolor = typearray.getcolor(r.styleable.dancingview_pointcolor, default_point_color);
    mballcolor = typearray.getcolor(r.styleable.dancingview_ballcolor, default_ball_color);
    typearray.recycle();
  }


  private void initcontroller() {
    mdowncontroller = valueanimator.offloat(0, 1);
    mdowncontroller.setduration(default_down_duration);
    mdowncontroller.setinterpolator(new decelerateinterpolator());
    mdowncontroller.addupdatelistener(new valueanimator.animatorupdatelistener() {
      @override
      public void onanimationupdate(valueanimator animation) {
        mdowndistance = max_offset_y * (float) animation.getanimatedvalue();
        postinvalidate();
      }
    });
    mdowncontroller.addlistener(new animator.animatorlistener() {
      @override
      public void onanimationstart(animator animation) {
        state = state_down;
      }

      @override
      public void onanimationend(animator animation) {
      }

      @override
      public void onanimationcancel(animator animation) {
      }

      @override
      public void onanimationrepeat(animator animation) {
      }
    });

    mupcontroller = valueanimator.offloat(0, 1);
    mupcontroller.setduration(default_up_duration);
    mupcontroller.setinterpolator(new dancinginterpolator());
    mupcontroller.addupdatelistener(new valueanimator.animatorupdatelistener() {
      @override
      public void onanimationupdate(valueanimator animation) {
        mupdistance = max_offset_y * (float) animation.getanimatedvalue();
        if (mupdistance >= max_offset_y) {
          //进入*落体状态
          isbounced = true;
          if (!mfreedowncontroller.isrunning() && !mfreedowncontroller.isstarted() && !isballfreeup) {
            mfreedowncontroller.start();
          }
        }
        postinvalidate();
      }
    });
    mupcontroller.addlistener(new animator.animatorlistener() {
      @override
      public void onanimationstart(animator animation) {
        state = state_up;
      }

      @override
      public void onanimationend(animator animation) {
        ismupcontrollerdied = true;
      }

      @override
      public void onanimationcancel(animator animation) {
      }

      @override
      public void onanimationrepeat(animator animation) {

      }
    });

    mfreedowncontroller = valueanimator.offloat(0, 8f);
    mfreedowncontroller.setduration(default_freedown_duration);
    mfreedowncontroller.setinterpolator(new decelerateinterpolator());
    mfreedowncontroller.addupdatelistener(new valueanimator.animatorupdatelistener() {
      @override
      public void onanimationupdate(valueanimator animation) {
        //该公式解决上升减速 和 下降加速
        float t = (float) animation.getanimatedvalue();
        freeballdistance = 40 * t - 5 * t * t;

        if (ismupcontrollerdied) {//往上抛,到临界点
          postinvalidate();
        }
      }
    });
    mfreedowncontroller.addlistener(new animator.animatorlistener() {
      @override
      public void onanimationstart(animator animation) {
        isballfreeup = true;
      }

      @override
      public void onanimationend(animator animation) {
        isanimationshowing = false;
        //循环第二次
        startanimations();
      }

      @override
      public void onanimationcancel(animator animation) {
      }

      @override
      public void onanimationrepeat(animator animation) {
      }
    });

    animatorset = new animatorset();
    animatorset.play(mdowncontroller).before(mupcontroller);
    animatorset.addlistener(new animator.animatorlistener() {
      @override
      public void onanimationstart(animator animation) {
        isanimationshowing = true;
      }

      @override
      public void onanimationend(animator animation) {
      }

      @override
      public void onanimationcancel(animator animation) {
      }

      @override
      public void onanimationrepeat(animator animation) {
      }
    });
  }

  /**
   * 启动动画,外部调用
   */
  public void startanimations() {
    if (isanimationshowing) {
      return;
    }
    if (animatorset.isrunning()) {
      animatorset.end();
      animatorset.cancel();
    }
    isbounced = false;
    isballfreeup = false;
    ismupcontrollerdied = false;

    animatorset.start();
  }


  @override
  protected void ondraw(canvas canvas) {
    super.ondraw(canvas);


    // 一条绳子用左右两部分的二阶贝塞尔曲线组成
    mpaint.setcolor(mlinecolor);
    mpath.reset();
    //起始点
    mpath.moveto(getwidth() / 2 - mlinewidth / 2, getheight() / 2);

    if (state == state_down) {//下落
      /**************绘制绳子开始*************/
      //左部分 的贝塞尔
      mpath.quadto((float) (getwidth() / 2 - mlinewidth / 2 + mlinewidth * 0.375), getheight() / 2 + mdowndistance,
          getwidth() / 2, getheight() / 2 + mdowndistance);
      //右部分 的贝塞尔
      mpath.quadto((float) (getwidth() / 2 + mlinewidth / 2 - mlinewidth * 0.375), getheight() / 2 + mdowndistance,
          getwidth() / 2 + mlinewidth / 2, getheight() / 2);

      mpaint.setstyle(paint.style.stroke);
      canvas.drawpath(mpath, mpaint);
      /**************绘制绳子结束*************/


      /**************绘制弹跳小球开始*************/
      mpaint.setstyle(paint.style.fill);
      mpaint.setcolor(mballcolor);
      canvas.drawcircle(getwidth() / 2, getheight() / 2 + mdowndistance - ball_radius, ball_radius, mpaint);
      /**************绘制弹跳小球结束*************/
    } else if (state == state_up) { //向上弹
      /**************绘制绳子开始*************/
      //左部分的贝塞尔
      mpath.quadto((float) (getwidth() / 2 - mlinewidth / 2 + mlinewidth * 0.375), getheight() / 2 + 50 - mupdistance,
          getwidth() / 2,
          getheight() / 2 + (50 - mupdistance));

      //右部分的贝塞尔
      mpath.quadto((float) (getwidth() / 2 + mlinewidth / 2 - mlinewidth * 0.375), getheight() / 2 + 50 - mupdistance,
          getwidth() / 2 + mlinewidth / 2,
          getheight() / 2);

      mpaint.setstyle(paint.style.stroke);
      canvas.drawpath(mpath, mpaint);
      /**************绘制绳子结束*************/

      mpaint.setstyle(paint.style.fill);
      mpaint.setcolor(mballcolor);

      //弹性小球,*落体
      if (!isbounced) {
        //上升
        canvas.drawcircle(getwidth() / 2, getheight() / 2 + (max_offset_y - mupdistance) - ball_radius, ball_radius, mpaint);
      } else {
        //*落体
        canvas.drawcircle(getwidth() / 2, getheight() / 2 - freeballdistance - ball_radius, ball_radius, mpaint);
      }
    }
    mpaint.setcolor(mponitcolor);
    mpaint.setstyle(paint.style.fill);
    canvas.drawcircle(getwidth() / 2 - mlinewidth / 2, getheight() / 2, ponit_radius, mpaint);
    canvas.drawcircle(getwidth() / 2 + mlinewidth / 2, getheight() / 2, ponit_radius, mpaint);
  }

  @override
  public void surfacecreated(surfaceholder holder) {
    canvas canvas = holder.lockcanvas();//锁定整个surfaceview对象,获取该surface上的canvas.
    draw(canvas);
    holder.unlockcanvasandpost(canvas);//释放画布,提交修改
  }

  @override
  public void surfacechanged(surfaceholder holder, int format, int width, int height) {
  }

  @override
  public void surfacedestroyed(surfaceholder holder) {
  }
}

2.dancinginterpolator.java

 public class dancinginterpolator implements interpolator {
  @override
  public float getinterpolation(float input) {
    return (float) (1 - math.exp(-3 * input) * math.cos(10 * input));
  }
}

3.自定义属性 styles.xml

<declare-styleable name="dancingview">
    <attr name="linewidth" format="dimension" />
    <attr name="lineheight" format="dimension" />
    <attr name="pointcolor" format="reference|color" />
    <attr name="linecolor" format="reference|color" />
    <attr name="ballcolor" format="reference|color" />
</declare-styleable>

注意:颜色、尺寸、参数可以自己测试,调整。

以上就是本文的全部内容,希望对大家的学习和工作能有所帮助哦。