国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android動畫之小球擬合動畫實例

2019-12-12 02:32:52
字體:
來源:轉載
供稿:網友

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, 0, mRadiusSmall, Path.Direction.CW);      mPathCircle.addCircle(mRadiusSmall / 2f * mFraction * 3, 0, mRadiusSmall, Path.Direction.CW);    } else {      float distance = (mFraction - 1 / 3f) / (2 / 3f) * (mRadiusSmall * 2 + mRadiusSmall / 2f);      mPathCircle.addCircle(-mRadiusSmall / 2f - distance, 0, mRadiusSmall, Path.Direction.CW);      mPathCircle.addCircle(mRadiusSmall / 2f + distance, 0, mRadiusSmall, 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], mPointCtrl[1], mPointData[2], mPointData[3]);    mPathBezier.lineTo(mPointData[4], mPointData[5]);    mPathBezier.quadTo(mPointCtrl[2], mPointCtrl[3], mPointData[6], mPointData[7]);    mPathBezier2.reset();    mPathBezier2.moveTo(-mPointData[0], mPointData[1]);    mPathBezier2.quadTo(-mPointCtrl[0], mPointCtrl[1], -mPointData[2], mPointData[3]);    mPathBezier2.lineTo(-mPointData[4], mPointData[5]);    mPathBezier2.quadTo(-mPointCtrl[2], mPointCtrl[3], -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, 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, distance, mDistanceBezier, distance, topY);        mPathBezier.lineTo(distance, -topY);        mPathBezier.cubicTo(distance, -mDistanceBezier, -distance, -mDistanceBezier, -distance, -topY);        mPathBezier.close();        return;      }    }    mPathBezier.lineTo(distance, -topY);    mPathBezier.cubicTo(distance, -distanceBezier, -distance, -distanceBezier, -distance, -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, 0, x + mRadiusSmall + mRadiusSmall * (4 - mFraction * 4), 0);    mPathBezier.quadTo(x, 0, x, -mRadiusSmall);    mPathBezier.lineTo(x, mRadiusSmall);    mPathBezier.moveTo(-x, mRadiusSmall);    mPathBezier.quadTo(-x, 0, -x - mRadiusSmall - mRadiusSmall * (4 - mFraction * 4), 0);    mPathBezier.quadTo(-x, 0, -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();  }}

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 明溪县| 八宿县| 盐池县| 盖州市| 榆树市| 离岛区| 益阳市| 浮山县| 濮阳县| 凤冈县| 大足县| 五家渠市| 洪雅县| 景泰县| 额尔古纳市| 孙吴县| 延吉市| 岳普湖县| 宜黄县| 临汾市| 古蔺县| 邯郸县| 石阡县| 顺义区| 嘉祥县| 城步| 兰州市| 淳化县| 宜阳县| 六盘水市| 青龙| 如皋市| 准格尔旗| 马尔康县| 丰原市| 叙永县| 蒲城县| 北京市| 龙川县| 顺平县| 金溪县|