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

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

 更新時間:2017年07月03日 15:49:05   投稿:lqh  
這篇文章主要介紹了Android動畫之小球擬合動畫實例的相關資料,需要的朋友可以參考下

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

實現(xiàn)效果:

動畫組成:

1.通過三階貝塞爾曲線來擬合圓,擬合系數(shù)的由來,以及怎么選控制點.

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;

/**
 * 這個例子中,大家可以發(fā)現(xiàn)作者的擬合做的并不是很好,連接的地方比較生硬,大家可以思考下如何改善
 * 貝塞爾曲線繪制比較復雜,大家在學習過程中,可以仿照示例中的,將輔助點和線繪制出來,這樣會看的更清楚一點
 */
public class BallShapeChangeView extends View {

  // 使用貝塞爾曲線來擬合圓的magic number
  //C 是三階貝塞爾曲線擬合 圓的 誤差最小  獲得控制點的參數(shù).
  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個數(shù)據(jù)點 順時針排序,從左邊開始
  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];
    }
    //當動畫執(zhí)行進度大于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();
  }
}


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

相關文章

  • Android IntentService詳解及使用實例

    Android IntentService詳解及使用實例

    這篇文章主要介紹了Android IntentService詳解及使用實例的相關資料,需要的朋友可以參考下
    2017-03-03
  • Flutter之可滾動組件子項緩存?KeepAlive詳解

    Flutter之可滾動組件子項緩存?KeepAlive詳解

    這篇文章主要為大家詳細介紹了Flutter之可滾動組件子項緩存?KeepAlive,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Android-SPI學習筆記

    Android-SPI學習筆記

    這篇文章主要介紹了Android-SPI的相關資料,幫助大家更好的理解和學習使用Android,感興趣的朋友可以了解下
    2021-02-02
  • Android自定義ViewGroup實現(xiàn)側滑菜單

    Android自定義ViewGroup實現(xiàn)側滑菜單

    這篇文章主要為大家詳細介紹了Android如何通過自定義ViewGroup實現(xiàn)側滑菜單,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2023-01-01
  • android中用xml文件實現(xiàn)帶邊框背景效果的方法

    android中用xml文件實現(xiàn)帶邊框背景效果的方法

    這篇文章主要給大家介紹了在android中xml文件實現(xiàn)帶邊框背景效果的方法,其實實現(xiàn)的功能不是很難,僅作記錄,幫助需要的朋友們做個參考,需要的朋友們下面來一起看看吧。
    2017-06-06
  • Android使用 Coroutine + Retrofit打造簡單的HTTP請求庫

    Android使用 Coroutine + Retrofit打造簡單的HTTP請求庫

    這篇文章主要介紹了Android使用 Coroutine + Retrofit打造簡單的HTTP請求庫,幫助大家更好的理解和學習使用Android,感興趣的朋友可以了解下
    2021-03-03
  • Android Flutter實現(xiàn)3D動畫效果示例詳解

    Android Flutter實現(xiàn)3D動畫效果示例詳解

    在Flutter中提供了AnimatedWidget組件用于構建可復用的動畫組件。本文我們用AnimatedWidget來實現(xiàn)組件的3D旋轉效果,感興趣的可以了解一下
    2022-03-03
  • android中px、sp與dp之間進行轉換詳解

    android中px、sp與dp之間進行轉換詳解

    android中在xml布局中我們可以使用dp和px都可以,但是在代碼中,很多方法只提供了設置px的方法,這時候就需要用到dp和px相互切換了,下面這篇文章主要給大家介紹了關于android中px、sp與dp之間進行轉換的相關資料,需要的朋友可以參考下
    2022-08-08
  • Android Chronometer控件實現(xiàn)計時器函數(shù)詳解

    Android Chronometer控件實現(xiàn)計時器函數(shù)詳解

    這篇文章主要為大家詳細介紹了Android Chronometer控件實現(xiàn)計時器函數(shù),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-04-04
  • Android頁面中可編輯與不可編輯切換的實現(xiàn)

    Android頁面中可編輯與不可編輯切換的實現(xiàn)

    這篇文章主要給大家介紹了關于在Android頁面中可編輯與不可編輯切換的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-07-07

最新評論