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

首頁 > 系統(tǒng) > Android > 正文

Android中PathMeasure仿支付寶支付動畫

2019-10-22 18:30:37
字體:
供稿:網(wǎng)友

前言

在 Android 自定義 View 中,Path 可能用的比較多,PathMeasure 可能用的比較少,就我而言,以前也沒有使用過 PathMeasure 這個(gè) api,看到別人用 PathMeasure 和 ValueAnimator 結(jié)合在一起完成了很好的動畫效果,于是我也學(xué)習(xí)下 PathMeasure ,此處記錄下。

PathMeasure

構(gòu)造器:

Android,PathMeasure,支付寶

forceClosed 含義:

// 創(chuàng)建一個(gè) Path 對象path = new Path();path.moveTo(20, 20);path.lineTo(200, 20);path.lineTo(200, 400);

在onDraw(Canvas canvas) 中繪制 path

@Override protected void onDraw(Canvas canvas) {  destPath.reset();  destPath.lineTo(0, 0);  pathMeasure.setPath(path, true);  Log.e("debug", "PathMeasure.getLength() = " + pathMeasure.getLength());  pathMeasure.getSegment(0, pathMeasure.getLength() * curValue, destPath, true);canvas.drawPath(destPath, paint); // 繪制線段路徑 }

當(dāng) pathMeasure.setPath(path,false) 時(shí):

Android,PathMeasure,支付寶

Android,PathMeasure,支付寶

當(dāng) pathMeasure.setPath(path,true) 時(shí):

Android,PathMeasure,支付寶

Android,PathMeasure,支付寶

可以看到:當(dāng) forceClosed = true 時(shí), path 進(jìn)行了閉合,相應(yīng)的 path 長度也變長了,即 算上了斜邊的長度。

仿支付寶支付動畫 View - LoadingView

效果:

Android,PathMeasure,支付寶

思路:

繪制對號,叉號,主要是通過 ValueAnimator 結(jié)合 getSegment() 不斷繪制新的弧形段,其中,叉號由兩個(gè) path 組成,在第一個(gè) path 繪制完成時(shí),需要調(diào)用 pathMeasure.nextContour() 跳轉(zhuǎn)到另一個(gè) path。

getSegment() 將獲取的片段填充到 destPath 中,在 Android 4.4 及以下版本中,不能繪制,需要調(diào)用 destPath.reset(),destPath.line(0,0)

LoadingView 完整代碼:

 

public class LoadingView extends View {  private final int DEFAULT_COLOR = Color.BLACK; // 默認(rèn)圓弧顏色  private final int DEFAULT_STROKE_WIDTH = dp2Px(2); // 默認(rèn)圓弧寬度  private final boolean DEFAULT_IS_SHOW_RESULT = false; // 默認(rèn)不顯示加載結(jié)果  private final int DEFAULT_VIEW_WIDTH = dp2Px(50); // 控件默認(rèn)寬度  private final int DEFAULT_VIEW_HEIGHT = dp2Px(50); // 控件默認(rèn)高度  private int color; // 圓弧顏色  private int strokeWidth;  // 圓弧寬度  private boolean isShowResult;  // 是否顯示加載結(jié)果狀態(tài)  private Paint paint; // 畫筆  private int mWidth; // 控件寬度  private int mHeight; // 控件高度  private int radius;  // 圓弧所在圓的半徑  private int halfStrokeWidth; // 畫筆寬度的一半  private int rotateDelta = 4;  private int curAngle = 0;  private int minAngle = -90;  private int startAngle = -90; // 上方頂點(diǎn)  private int endAngle = 0;  private RectF rectF;  private StateEnum stateEnum = StateEnum.LOADING;  private Path successPath;  private Path rightFailPath;  private Path leftFailPath;  private ValueAnimator successAnimator;  private ValueAnimator rightFailAnimator;  private ValueAnimator leftFailAnimator;  private PathMeasure pathMeasure;  private float successValue;  private float rightFailValue;  private float leftFailValue;  private Path destPath;  private AnimatorSet animatorSet;  public LoadingView(Context context) {    this(context, null);  }  public LoadingView(Context context, AttributeSet attrs) {    super(context, attrs);    init(context, attrs);  }  private void init(Context context, AttributeSet attrs) {    TypedArray typedArray = null;    try {      typedArray = context.obtainStyledAttributes(attrs, R.styleable.LoadingView);      color = typedArray.getColor(R.styleable.LoadingView_color, DEFAULT_COLOR);      strokeWidth = (int) typedArray.getDimension(R.styleable.LoadingView_storkeWidth, DEFAULT_STROKE_WIDTH);      isShowResult = typedArray.getBoolean(R.styleable.LoadingView_isShowResult, DEFAULT_IS_SHOW_RESULT);    } catch (Exception e) {      e.printStackTrace();    } finally {      if (typedArray != null) {        typedArray.recycle();      }    }    paint = createPaint(color, strokeWidth, Paint.Style.STROKE);  }  @Override  protected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    mWidth = w;    mHeight = h;    Log.i("debug", "getMeasureWidth() = " + getMeasuredWidth());    Log.i("debug", "getMeasureHeight() = " + getMeasuredHeight());    radius = Math.min(mWidth, mHeight) / 2;    halfStrokeWidth = strokeWidth / 2;    rectF = new RectF(halfStrokeWidth - radius, halfStrokeWidth - radius,        radius - halfStrokeWidth, radius - halfStrokeWidth);    // success path    successPath = new Path();    successPath.moveTo(-radius * 2 / 3f, 0f);    successPath.lineTo(-radius / 8f, radius / 2f);    successPath.lineTo(radius / 2, -radius / 3);    // fail path ,right top to left bottom    rightFailPath = new Path();    rightFailPath.moveTo(radius / 3f, -radius / 3f);    rightFailPath.lineTo(-radius / 3f, radius / 3f);    // fail path, left top to right bottom    leftFailPath = new Path();    leftFailPath.moveTo(-radius / 3f, -radius / 3f);    leftFailPath.lineTo(radius / 3f, radius / 3f);    pathMeasure = new PathMeasure();    destPath = new Path();    initSuccessAnimator();    initFailAnimator();  }  private void initSuccessAnimator() {//    pathMeasure.setPath(successPath, false);    successAnimator = ValueAnimator.ofFloat(0, 1f);    successAnimator.setDuration(1000);    successAnimator.setInterpolator(new LinearInterpolator());    successAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @Override      public void onAnimationUpdate(ValueAnimator animation) {        successValue = (float) animation.getAnimatedValue();        invalidate();      }    });  }  private void initFailAnimator() {//    pathMeasure.setPath(rightFailPath, false);    rightFailAnimator = ValueAnimator.ofFloat(0, 1f);    rightFailAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @Override      public void onAnimationUpdate(ValueAnimator animation) {        rightFailValue = (float) animation.getAnimatedValue();        invalidate();      }    });//    pathMeasure.setPath(leftFailPath, false);    leftFailAnimator = ValueAnimator.ofFloat(0, 1f);    leftFailAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @Override      public void onAnimationUpdate(ValueAnimator animation) {        leftFailValue = (float) animation.getAnimatedValue();        invalidate();      }    });    animatorSet = new AnimatorSet();    animatorSet.play(leftFailAnimator).after(rightFailAnimator);    animatorSet.setDuration(500);    animatorSet.setInterpolator(new LinearInterpolator());  }  /**   * 測量控件的寬高,當(dāng)測量模式不是精確模式時(shí),設(shè)置默認(rèn)寬高   *   * @param widthMeasureSpec   * @param heightMeasureSpec   */  @Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    int widthMode = MeasureSpec.getMode(widthMeasureSpec);    int heightMode = MeasureSpec.getMode(heightMeasureSpec);    if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED) {      widthMeasureSpec = MeasureSpec.makeMeasureSpec(DEFAULT_VIEW_WIDTH, MeasureSpec.EXACTLY);    }    if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {      heightMeasureSpec = MeasureSpec.makeMeasureSpec(DEFAULT_VIEW_HEIGHT, MeasureSpec.EXACTLY);    }    super.onMeasure(widthMeasureSpec, heightMeasureSpec);  }  @Override  protected void onDraw(Canvas canvas) {    canvas.save();    canvas.translate(mWidth / 2, mHeight / 2);    destPath.reset();    destPath.lineTo(0, 0);  // destPath    if (stateEnum == StateEnum.LOADING) {      if (endAngle >= 300 || startAngle > minAngle) {        startAngle += 6;        if (endAngle > 20) {          endAngle -= 6;        }      }      if (startAngle > minAngle + 300) {        minAngle = startAngle;        endAngle = 20;      }      canvas.rotate(curAngle += rotateDelta, 0, 0);//旋轉(zhuǎn)rotateDelta=4的弧長      canvas.drawArc(rectF, startAngle, endAngle, false, paint);      // endAngle += 6 放在 drawArc()后面,是防止剛進(jìn)入時(shí),突兀的顯示了一段圓弧      if (startAngle == minAngle) {        endAngle += 6;      }      invalidate();    }    if (isShowResult) {      if (stateEnum == StateEnum.LOAD_SUCCESS) {        pathMeasure.setPath(successPath, false);        canvas.drawCircle(0, 0, radius - halfStrokeWidth, paint);        pathMeasure.getSegment(0, successValue * pathMeasure.getLength(), destPath, true);        canvas.drawPath(destPath, paint);      } else if (stateEnum == StateEnum.LOAD_FAILED) {        canvas.drawCircle(0, 0, radius - halfStrokeWidth, paint);        pathMeasure.setPath(rightFailPath, false);        pathMeasure.getSegment(0, rightFailValue * pathMeasure.getLength(), destPath, true);        if (rightFailValue == 1) {          pathMeasure.setPath(leftFailPath, false);          pathMeasure.nextContour();          pathMeasure.getSegment(0, leftFailValue * pathMeasure.getLength(), destPath, true);        }        canvas.drawPath(destPath, paint);      }    }    canvas.restore();  }  public void updateState(StateEnum stateEnum) {    this.stateEnum = stateEnum;    if (stateEnum == StateEnum.LOAD_SUCCESS) {      successAnimator.start();    } else if (stateEnum == StateEnum.LOAD_FAILED) {      animatorSet.start();    }  }  public enum StateEnum {    LOADING, // 正在加載    LOAD_SUCCESS,  // 加載成功,顯示對號    LOAD_FAILED   // 加載失敗,顯示叉號  }  /**   * 創(chuàng)建畫筆   *   * @param color    畫筆顏色   * @param strokeWidth 畫筆寬度   * @param style    畫筆樣式   * @return   */  private Paint createPaint(int color, int strokeWidth, Paint.Style style) {    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);    paint.setStrokeCap(Paint.Cap.ROUND);    paint.setStrokeJoin(Paint.Join.ROUND);    paint.setColor(color);    paint.setStrokeWidth(strokeWidth);    paint.setStyle(style);    return paint;  }  /**   * dp 轉(zhuǎn)換成 px   *   * @param dpValue   * @return   */  private int dp2Px(int dpValue) {    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, getResources().getDisplayMetrics());  }}

github : https://github.com/xing16/LoadingView

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 夹江县| 宁南县| 东至县| 沾益县| 兴义市| 新沂市| 宁安市| 陇西县| 溧水县| 石屏县| 息烽县| 灯塔市| 盐津县| 敖汉旗| 江西省| 龙山县| 皋兰县| 台中县| 彰化市| 天镇县| 广德县| 静海县| 吉木乃县| 金秀| 东阳市| 上虞市| 永和县| 岳普湖县| 庆阳市| 永济市| 聂拉木县| 泸水县| 远安县| 浦城县| 鹤岗市| 木里| 五常市| 米林县| 彰化市| 太保市| 荃湾区|