Android动画之小球拟合动画实例

Android动画之小球拟合动画实例,第1张

概述Android动画之小球拟合动画实例实现效果:动画组成:1.通过三阶贝塞尔曲线来拟合圆,拟合系数的由来,以及怎么选控制点.

AndroID动画之小球拟合动画实例

实现效果:

动画组成:

1.通过三阶贝塞尔曲线来拟合圆,拟合系数的由来,以及怎么选控制点.

2.利用画布canvas.translate,以及scale,rotate的方法,来渐变绘制的过程.

3.熟悉拟合过程.

4.不熟悉的话,先绘制辅助点的移动路线,对理解两个圆的分裂的拟合过程有好处.

package com.example.administrator.animationworkdemo.vIEws;import androID.animation.ValueAnimator;import androID.content.Context;import androID.graphics.Canvas;import androID.graphics.Paint;import androID.graphics.Path;import androID.graphics.PathMeasure;import androID.util.AttributeSet;import androID.vIEw.VIEw;import java.util.concurrent.CyclicbarrIEr;/** * 这个例子中,大家可以发现作者的拟合做的并不是很好,连接的地方比较生硬,大家可以思考下如何改善 * 贝塞尔曲线绘制比较复杂,大家在学习过程中,可以仿照示例中的,将辅助点和线绘制出来,这样会看的更清楚一点 */public class BallShapeChangeVIEw extends VIEw {  // 使用贝塞尔曲线来拟合圆的magic number  //C 是三阶贝塞尔曲线拟合 圆的 误差最小  获得控制点的参数.  private static final float C = 0.551915024494f;  private Paint mPaint;  private int mRadiusBig = 120,mRadiusSmall = (int) (mRadiusBig / 2f),mWIDth,mHeight,mMimWIDth = (int) (mRadiusSmall * 2 * 3)/*fill vIEw mim wIDth*/;  private float mFraction = 0,mFractionDegree = 0,/*degree*/      mLength,mdistanceBezIEr;  private Path mPathCircle,mPathBezIEr;  private ValueAnimator mValueAnimator;  private float[] mPointData = new float[8];// 4个数据点 顺时针排序,从左边开始  private float[] mPointCtrl = new float[16];// 8个控制点  private float[] mPos = new float[2];  private PathMeasure mPathMeasure;  private Path mPathBezIEr2;  public BallShapeChangeVIEw(Context context,AttributeSet attrs) {    super(context,attrs);    mPaint = new Paint();    mPaint.setStyle(Paint.Style.FILL);    mPaint.setcolor(0xFF7C191E);    mPaint.setAntiAlias(true);    mPathCircle = new Path();    mPathBezIEr = new Path();    mPathBezIEr2 = new Path();    mPathMeasure = new PathMeasure();    mValueAnimator = ValueAnimator.offloat(0,1,0);    mValueAnimator.setDuration(3000);    mValueAnimator.setRepeatCount(Integer.MAX_VALUE);    mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @OverrIDe      public voID onAnimationUpdate(ValueAnimator animation) {        mFraction = (float) animation.getAnimatedValue();        mFractionDegree = animation.getAnimatedFraction();        invalIDate();      }    });  }  @OverrIDe  protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) {    // 为了能够更好的控制绘制的大小和位置,当然,初学者写死也是可以的    super.onMeasure(wIDthMeasureSpec,heightmeasureSpec);    mWIDth = MeasureSpec.getSize(wIDthMeasureSpec);    mHeight = MeasureSpec.getSize(heightmeasureSpec);    int wIDthMode = MeasureSpec.getMode(wIDthMeasureSpec);    int heightmode = MeasureSpec.getMode(heightmeasureSpec);    if (wIDthMode != MeasureSpec.AT_MOST && heightmode != MeasureSpec.AT_MOST) {      if (mWIDth < mMimWIDth)        mWIDth = mMimWIDth;      if (mHeight < mMimWIDth)        mHeight = mMimWIDth;    } else if (wIDthMeasureSpec != MeasureSpec.AT_MOST) {      if (mWIDth < mMimWIDth)        mWIDth = mMimWIDth;    } else if (heightmeasureSpec != MeasureSpec.AT_MOST) {      if (mHeight < mMimWIDth)        mHeight = mMimWIDth;    }    setMeasuredDimension(mWIDth,mHeight);  }  @OverrIDe  protected voID onDraw(Canvas canvas) {    super.onDraw(canvas);    // 通过mFraction来控制绘图的过程,这是常用的一种方式    canvas.translate(mWIDth / 2,mHeight / 2);    canvas.scale(1,-1);    canvas.rotate(-360 * mFractionDegree);    setDoubleCirClePath();    canvas.drawPath(mPathCircle,mPaint);    if (mFraction < (1 / 3f)) {// 缩小大圆      setCirclePath();      canvas.drawPath(mPathCircle,mPaint);    } else if (mFraction < 3 / 4f) {// 画贝塞尔曲线      setBezIErPath2();      canvas.drawPath(mPathBezIEr,mPaint);      canvas.drawPath(mPathBezIEr2,mPaint);    } else {// 画分离      //setLastBezIErPath();      //canvas.drawPath(mPathBezIEr,mPaint);    }  }  private voID setDoubleCirClePath() {    mPathCircle.reset();    if (mFraction < (1 / 3f)) {      mPathCircle.addCircle(-mRadiusSmall / 2f * mFraction * 3,mRadiusSmall,Path.Direction.CW);      mPathCircle.addCircle(mRadiusSmall / 2f * mFraction * 3,Path.Direction.CW);    } else {      float distance = (mFraction - 1 / 3f) / (2 / 3f) * (mRadiusSmall * 2 + mRadiusSmall / 2f);      mPathCircle.addCircle(-mRadiusSmall / 2f - distance,Path.Direction.CW);      mPathCircle.addCircle(mRadiusSmall / 2f + distance,Path.Direction.CW);    }  }  // mFraction 0 ~ 1/3  private voID setCirclePath() {    mPointData[0] = -mRadiusBig + mRadiusSmall / 2f * mFraction * 3f;    mPointData[1] = 0;    mPointData[2] = 0;    mPointData[3] = mRadiusBig - mRadiusBig / 2f * mFraction * 3f;//0到1 的三分之一 用来给大圆做效果;    mPointData[4] = mRadiusBig - mRadiusSmall / 2f * mFraction * 3f;    mPointData[5] = 0;    mPointData[6] = mPointData[2];    mPointData[7] = -mPointData[3];    mPointCtrl[0] = mPointData[0];// x轴一样    mPointCtrl[1] = mRadiusBig * C;// y轴向下的    mPointCtrl[2] = mPointData[2] - mRadiusBig * C;    mPointCtrl[3] = mPointData[3];// y轴一样    mPointCtrl[4] = mPointData[2] + mRadiusBig * C;    mPointCtrl[5] = mPointData[3];    mPointCtrl[6] = mPointData[4];    mPointCtrl[7] = mPointCtrl[1];    mPointCtrl[8] = mPointData[4];    mPointCtrl[9] = -mPointCtrl[1];    mPointCtrl[10] = mPointCtrl[4];    mPointCtrl[11] = mPointData[7];    mPointCtrl[12] = mPointCtrl[2];    mPointCtrl[13] = mPointData[7];    mPointCtrl[14] = mPointData[0];    mPointCtrl[15] = -mPointCtrl[1];    mPathCircle.reset();    mPathCircle.moveto(mPointData[0],mPointData[1]);    mPathCircle.cubicTo(mPointCtrl[0],mPointCtrl[1],mPointCtrl[2],mPointCtrl[3],mPointData[2],mPointData[3]);    mPathCircle.cubicTo(mPointCtrl[4],mPointCtrl[5],mPointCtrl[6],mPointCtrl[7],mPointData[4],mPointData[5]);    mPathCircle.cubicTo(mPointCtrl[8],mPointCtrl[9],mPointCtrl[10],mPointCtrl[11],mPointData[6],mPointData[7]);    mPathCircle.cubicTo(mPointCtrl[12],mPointCtrl[13],mPointCtrl[14],mPointCtrl[15],mPointData[0],mPointData[1]);  }  // mFraction 1/3 ~ 3/4  private voID setBezIErPath2() {    mPointData[0] = -mRadiusSmall / 2 - (mFraction - 1 / 3f) * mRadiusBig * 2f;    if (mFraction < 2 / 3f) {      mPointData[1] = -mRadiusSmall;    } else {      mPointData[1] = -mRadiusSmall + (mFraction - 2 / 3f) * 3 * mRadiusSmall;    }    if (mFraction < 3 / 4f) {      mPointData[2] = 0;    } else {      //当分裂超过一定程度让结束点的位置变远      mPointData[2] = (mFraction - 3 / 4f) * 16 * mPointData[0];    }    //当动画执行进度大于2/3时,此时该点接近于0    mPointData[3] = -mRadiusBig + mFraction * mRadiusBig * 1.5f < -0.01f * mRadiusBig ? -mRadiusBig + mFraction * mRadiusBig * 1.5f : 0.01f * -mRadiusBig;    mPointData[4] = mPointData[2];    mPointData[5] = -mPointData[3];    mPointData[6] = mPointData[0];    mPointData[7] = -mPointData[1];    mPointCtrl[0] = mPointData[0] + mRadiusSmall;    mPointCtrl[1] = mPointData[3];    mPointCtrl[2] = mPointData[0] + mRadiusSmall;    mPointCtrl[3] = -mPointData[3];    mPathBezIEr.reset();    mPathBezIEr.moveto(mPointData[0],mPointData[1]);    mPathBezIEr.quadTo(mPointCtrl[0],mPointData[3]);    mPathBezIEr.lineto(mPointData[4],mPointData[5]);    mPathBezIEr.quadTo(mPointCtrl[2],mPointData[7]);    mPathBezIEr2.reset();    mPathBezIEr2.moveto(-mPointData[0],mPointData[1]);    mPathBezIEr2.quadTo(-mPointCtrl[0],-mPointData[2],mPointData[3]);    mPathBezIEr2.lineto(-mPointData[4],mPointData[5]);    mPathBezIEr2.quadTo(-mPointCtrl[2],-mPointData[6],mPointData[7]);  }  // mFraction 1/3 ~ 3/4  private voID setBezIErPath() {    mPathBezIEr.reset();    float distance = (2 * mRadiusSmall + mRadiusSmall / 2f) * mFraction;    //float topY = mRadiusSmall * (1 - 0.6f * mFraction);    float topY = mRadiusSmall - mRadiusSmall * (mFraction - 1 / 3f);    float distanceBezIEr = topY - distance * C * (0.5f + 0.5f * mFraction);    if (mdistanceBezIEr != 0 && distanceBezIEr < (mdistanceBezIEr)) {      distanceBezIEr = mdistanceBezIEr;    }    mPathBezIEr.moveto(-distance,topY);    mPathBezIEr.cubicTo(-distance,distanceBezIEr,distance,topY);    if (mdistanceBezIEr == 0) {      mPathMeasure.setPath(mPathBezIEr,false);      mLength = mPathMeasure.getLength();      mPathMeasure.getPosTan(mLength / 2,mPos,null);      if (mPos[1] <= 8) {        mdistanceBezIEr = distanceBezIEr;        mPathBezIEr.reset();        mPathBezIEr.moveto(-distance,topY);        mPathBezIEr.cubicTo(-distance,mdistanceBezIEr,topY);        mPathBezIEr.lineto(distance,-topY);        mPathBezIEr.cubicTo(distance,-mdistanceBezIEr,-distance,-topY);        mPathBezIEr.close();        return;      }    }    mPathBezIEr.lineto(distance,-topY);    mPathBezIEr.cubicTo(distance,-distanceBezIEr,-topY);    mPathBezIEr.close();  }  // mFraction 3/4 ~ 1  private voID setLastBezIErPath() {    float x = -mRadiusSmall / 2f - (mFraction - 1 / 3f) / (2 / 3f) * (mRadiusSmall * 2 + mRadiusSmall / 2f);    mPathBezIEr.reset();    mPathBezIEr.moveto(x,mRadiusSmall);    mPathBezIEr.quadTo(x,x + mRadiusSmall + mRadiusSmall * (4 - mFraction * 4),0);    mPathBezIEr.quadTo(x,x,-mRadiusSmall);    mPathBezIEr.lineto(x,mRadiusSmall);    mPathBezIEr.moveto(-x,mRadiusSmall);    mPathBezIEr.quadTo(-x,-x - mRadiusSmall - mRadiusSmall * (4 - mFraction * 4),0);    mPathBezIEr.quadTo(-x,-x,-mRadiusSmall);    mPathBezIEr.lineto(-x,mRadiusSmall);    mPathBezIEr.close();  }  @OverrIDe  protected voID onAttachedToWindow() {    super.onAttachedToWindow();    if (!mValueAnimator.isRunning())      mValueAnimator.start();  }  @OverrIDe  protected voID onDetachedFromWindow() {    super.onDetachedFromWindow();    if (mValueAnimator.isRunning())      mValueAnimator.cancel();  }}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

总结

以上是内存溢出为你收集整理的Android动画之小球拟合动画实例全部内容,希望文章能够帮你解决Android动画之小球拟合动画实例所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1145844.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存