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

首頁 > 系統 > Android > 正文

Android自定義View實現仿駕考寶典顯示分數效果(收藏)

2019-10-23 19:44:13
字體:
來源:轉載
供稿:網友

小編最近發現,一些炫酷的view效果,通過需要自定義view和屬性動畫結合在一起,才能更容易的實現。

實現的效果圖如下:

android,自定義view,android仿駕考寶典

所用的知識有:

(1)自定義View中的 path ,主要用來繪制指示塊。

(2)屬性動畫-ValueAnimator,并設置屬性動畫的監聽器。

(3)根據屬性動畫是否結束的標志,決定是否繪制分數對應的描述文本內容。

實現步驟:

繼承自View,在構造函數中獲取自定義屬性和初始化操作(初始化畫筆)

private void obtainAttrs(Context context, AttributeSet attrs) {    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScoreView);    lineLength = typedArray.getDimension(R.styleable.ScoreView_lineLength, dp2Px(10));    lineColor = typedArray.getColor(R.styleable.ScoreView_lineColor, Color.WHITE);    typedArray.recycle();  }  private void init() {    arrowPaint = createPaint(Color.WHITE, 0, Paint.Style.FILL, 0);    arcPaint = createPaint(lineColor, dp2Px(1), Paint.Style.STROKE, 0);    bgPaint = createPaint(lineColor, dp2Px(1), Paint.Style.FILL, 0);    reachProgressPaint = createPaint(Color.WHITE, dp2Px(1), Paint.Style.FILL, 0);    arcReachPaint = createPaint(Color.WHITE, dp2Px(1), Paint.Style.STROKE, 0);    scoreTextPaint = createPaint(Color.WHITE, 0, Paint.Style.STROKE, dp2Px(26));    descTextPaint = createPaint(Color.WHITE, 0, Paint.Style.STROKE, dp2Px(16));  }

其中初始化畫筆抽取到一個函數中:

private Paint createPaint(int color, int strokeWidth, Paint.Style style, float textSize) {    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);    paint.setColor(color);    paint.setStrokeWidth(strokeWidth);    paint.setStyle(style);    paint.setStrokeJoin(Paint.Join.ROUND);    paint.setStrokeCap(Paint.Cap.ROUND);    paint.setTextSize(textSize);    return paint;  }

覆蓋 onSizeChanged() ,得到控件的寬高,并決定要繪制區域的大?。丶J設置了內邊距)

@Override  protected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    viewWidth = w;    viewHeight = h;    halfView = Math.min(viewWidth, viewHeight) / 2;  //寬度或高度中最小值的一半,即決定圓心的位置。    radius = (Math.min(viewWidth, viewHeight) - 2 * DEFAULT_PADDING) / 2; //繪制園的半徑是寬高除去默認內邊距  }

核心繪制代碼,覆蓋onDraw()方法,根據動畫是否結束的標志,決定是否繪制分數對應的文本。

@Override  protected void onDraw(Canvas canvas) {    super.onDraw(canvas);    drawArcBackground(canvas);    drawArcProgress(canvas);    drawScoreText(canvas);    if (isAnimEnd) {      drawDescText(canvas);    }  }

(1)繪制圓弧背景和灰色刻度背景。

 private void drawArcBackground(Canvas canvas) {    canvas.save();    canvas.translate(halfView, halfView);    //繪制圓弧    RectF rectF = new RectF(dp2Px(5) - radius, dp2Px(5) - radius, radius - dp2Px(5), radius - dp2Px(5));    canvas.drawArc(rectF, 120, 300, false, arcPaint);    //繪制刻度線    canvas.rotate(30);    for (int i = 0; i < 100; i++) {      canvas.drawLine(0, radius - dp2Px(15), 0,          radius - dp2Px(15) - lineLength,          bgPaint);      canvas.rotate(degree);    }    canvas.restore();  }

(2) 繪制刻度,根據ValueAnimator進行動畫的當前值curValue,來動態改變繪制指示塊和已達進度圓弧,從而實現從0開始移動到設定值的動畫效果。

private void drawArcProgress(Canvas canvas) {    canvas.save();    canvas.translate(halfView, halfView);    //繪制圓弧    RectF rectF = new RectF(dp2Px(5) - radius, dp2Px(5) - radius, radius - dp2Px(5), radius - dp2Px(5));    canvas.drawArc(rectF, 120, curValue * degree, false, arcReachPaint);    //繪制指示方塊,方塊是從0開始移動某一個位置的    canvas.rotate(30 + degree * curValue);    Path path = new Path();    path.moveTo(dp2Px(5), radius);    path.lineTo(dp2Px(5), radius - dp2Px(10));    path.lineTo(0, radius - dp2Px(15));    path.lineTo(-dp2Px(5), radius - dp2Px(10));    path.lineTo(-dp2Px(5), radius);    path.close();    canvas.drawPath(path, arrowPaint);    //繪制已經達到的刻度    canvas.restore();    canvas.save();    canvas.translate(halfView, halfView);    canvas.rotate(30);    for (int i = 0; i < curValue; i++) {      canvas.drawLine(0, radius - dp2Px(15), 0,          radius - dp2Px(15) - lineLength,          reachProgressPaint);      canvas.rotate(degree);    }    canvas.restore();  }

(3) 繪制分數文本。

private void drawScoreText(Canvas canvas) {    canvas.save();    canvas.translate(halfView, halfView);    String scoreText = curValue + "分";    float textLength = scoreTextPaint.measureText(scoreText);    canvas.drawText(scoreText, -textLength / 2, 0, scoreTextPaint);    canvas.restore();  }

(4) 動畫結束時,繪制最終分數對應的提示信息,該信息只有在動畫結束后,才會顯示出來。

private void drawDescText(Canvas canvas) {    canvas.save();    canvas.translate(halfView, halfView);    String desc = "";    if (curValue >= 90) {      desc = "車神";    } else {      desc = "馬路殺手";    }    float descLength = descTextPaint.measureText(desc);    canvas.drawText(desc, -descLength / 2, dp2Px(30), descTextPaint);    canvas.restore();    isAnimEnd = false; // isAnimEnd置為false,防止再次點擊start時,就顯示動畫結束時才能顯示的內容  }

(5)提供對外設置最大值的接口,決定最后的分數。

 /**   * 對外提供的接口,用于設置進度的最大值   *   * @param value   */  public void setMaxValue(int value) {    if (valueAnimator == null) {      valueAnimator = ValueAnimator.ofInt(0, value);    }    valueAnimator.setInterpolator(new LinearInterpolator());    valueAnimator.setDuration(30 * value);    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @Override      public void onAnimationUpdate(ValueAnimator animation) {        curValue = (int) animation.getAnimatedValue();        Log.i("debug", "curValue=" + curValue);        invalidate();      }    });    valueAnimator.addListener(new AnimatorListenerAdapter() {      @Override      public void onAnimationEnd(Animator animation) {        super.onAnimationEnd(animation);        isAnimEnd = true; //標記動畫結束        Log.i("debug", "onAnimationEnd");        Log.i("debug", "onAnimationEnd curValue = " + curValue);        invalidate();      }    });    valueAnimator.start();  }

完整代碼:

public class ScoreView extends View {  private final int DEFAULT_PADDING = dp2Px(5);  private final int DEFAULT_WIDTH = dp2Px(200);  //默認寬度為200dp  private final int DEFAULT_HEIGHT = dp2Px(200); //默認高度為200dp  private int viewWidth; //View寬度  private int viewHeight;  //View高度  private int halfView; //view寬度或高度的一半  private int radius;  //繪制圓形區域的半徑  private Paint bgPaint;  private Paint arrowPaint; //指示塊畫筆  private Paint arcPaint; //圓弧畫筆  private Paint arcReachPaint; //圓弧畫筆  private Paint reachProgressPaint; //已達刻度  private Paint scoreTextPaint;  //繪制分數文本  private Paint descTextPaint;  //繪制描述文本  private float degree = 3f; //相鄰刻度之間夾角大小為3度,角度制,不是弧度制  private float lineLength;  private int lineColor;  private int curValue;  //動畫進行的當前值  private ValueAnimator valueAnimator;  private boolean isAnimEnd = false;  public ScoreView(Context context) {    this(context, null);  }  public ScoreView(Context context, AttributeSet attrs) {    super(context, attrs);    obtainAttrs(context, attrs);    init();  }  private void obtainAttrs(Context context, AttributeSet attrs) {    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScoreView);    lineLength = typedArray.getDimension(R.styleable.ScoreView_lineLength, dp2Px(10));    lineColor = typedArray.getColor(R.styleable.ScoreView_lineColor, Color.WHITE);    typedArray.recycle();  }  private void init() {    arrowPaint = createPaint(Color.WHITE, 0, Paint.Style.FILL, 0);    arcPaint = createPaint(lineColor, dp2Px(1), Paint.Style.STROKE, 0);    bgPaint = createPaint(lineColor, dp2Px(1), Paint.Style.FILL, 0);    reachProgressPaint = createPaint(Color.WHITE, dp2Px(1), Paint.Style.FILL, 0);    arcReachPaint = createPaint(Color.WHITE, dp2Px(1), Paint.Style.STROKE, 0);    scoreTextPaint = createPaint(Color.WHITE, 0, Paint.Style.STROKE, dp2Px(26));    descTextPaint = createPaint(Color.WHITE, 0, Paint.Style.STROKE, dp2Px(16));  }  @Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    super.onMeasure(widthMeasureSpec, heightMeasureSpec);    setMeasuredDimension(measureSize(widthMeasureSpec, DEFAULT_WIDTH), measureSize(heightMeasureSpec, DEFAULT_HEIGHT));  }  private int measureSize(int measureSpec, int defaultSize) {    int measureSize = defaultSize;    int mode = MeasureSpec.getMode(measureSpec);    int size = MeasureSpec.getSize(measureSpec);    if (mode == MeasureSpec.EXACTLY) {      measureSize = size;    } else {      if (mode == MeasureSpec.AT_MOST) {        measureSize = Math.min(defaultSize, size);      }    }    return measureSize;  }  @Override  protected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    viewWidth = w;    viewHeight = h;    halfView = Math.min(viewWidth, viewHeight) / 2;  //寬度或高度中最小值的一半,即圓形的位置    radius = (Math.min(viewWidth, viewHeight) - 2 * DEFAULT_PADDING) / 2; //半徑是寬高除去默認內邊距的  }  @Override  protected void onDraw(Canvas canvas) {    super.onDraw(canvas);    drawArcBackground(canvas);    drawArcProgress(canvas);    drawScoreText(canvas);    if (isAnimEnd) {      drawDescText(canvas);    }  }  private void drawScoreText(Canvas canvas) {    canvas.save();    canvas.translate(halfView, halfView);    String scoreText = curValue + "分";    float textLength = scoreTextPaint.measureText(scoreText);    canvas.drawText(scoreText, -textLength / 2, 0, scoreTextPaint);    canvas.restore();  }  /**   * 繪制文本   *   * @param canvas   */  private void drawDescText(Canvas canvas) {    canvas.save();    canvas.translate(halfView, halfView);    String desc = "";    if (curValue >= 90) {      desc = "車神";    } else {      desc = "馬路殺手";    }    float descLength = descTextPaint.measureText(desc);    canvas.drawText(desc, -descLength / 2, dp2Px(30), descTextPaint);    canvas.restore();    isAnimEnd = false; // isAnimEnd置為false,防止再次點擊start時,就顯示動畫結束時才能顯示的內容  }  /**   * 繪制進度   *   * @param canvas   */  private void drawArcProgress(Canvas canvas) {    canvas.save();    canvas.translate(halfView, halfView);    //繪制圓弧    RectF rectF = new RectF(dp2Px(5) - radius, dp2Px(5) - radius, radius - dp2Px(5), radius - dp2Px(5));    canvas.drawArc(rectF, 120, curValue * degree, false, arcReachPaint);    //繪制指示方塊,方塊是從0開始移動某一個位置的    canvas.rotate(30 + degree * curValue);    Path path = new Path();    path.moveTo(dp2Px(5), radius);    path.lineTo(dp2Px(5), radius - dp2Px(10));    path.lineTo(0, radius - dp2Px(15));    path.lineTo(-dp2Px(5), radius - dp2Px(10));    path.lineTo(-dp2Px(5), radius);    path.close();    canvas.drawPath(path, arrowPaint);    //繪制已經達到的刻度    canvas.restore();    canvas.save();    canvas.translate(halfView, halfView);    canvas.rotate(30);    for (int i = 0; i < curValue; i++) {      canvas.drawLine(0, radius - dp2Px(15), 0,          radius - dp2Px(15) - lineLength,          reachProgressPaint);      canvas.rotate(degree);    }    canvas.restore();  }  /**   * 繪制背景   *   * @param canvas   */  private void drawArcBackground(Canvas canvas) {    canvas.save();    canvas.translate(halfView, halfView);    //繪制圓弧    RectF rectF = new RectF(dp2Px(5) - radius, dp2Px(5) - radius, radius - dp2Px(5), radius - dp2Px(5));    canvas.drawArc(rectF, 120, 300, false, arcPaint);    //繪制刻度線    canvas.rotate(30);    for (int i = 0; i < 100; i++) {      canvas.drawLine(0, radius - dp2Px(15), 0,          radius - dp2Px(15) - lineLength,          bgPaint);      canvas.rotate(degree);    }    canvas.restore();  }  /**   * 創建畫筆   *   * @param color   * @param strokeWidth   * @param style   * @param textSize   * @return   */  private Paint createPaint(int color, int strokeWidth, Paint.Style style, float textSize) {    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);    paint.setColor(color);    paint.setStrokeWidth(strokeWidth);    paint.setStyle(style);    paint.setStrokeJoin(Paint.Join.ROUND);    paint.setStrokeCap(Paint.Cap.ROUND);    paint.setTextSize(textSize);    return paint;  }  /**   * dp轉換成px   *   * @param dpValue   * @return   */  private int dp2Px(int dpValue) {    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,        dpValue, getResources().getDisplayMetrics());  }  /**   * 對外提供的接口,用于設置進度的最大值   *   * @param value   */  public void setMaxValue(int value) {    if (valueAnimator == null) {      valueAnimator = ValueAnimator.ofInt(0, value);    }    valueAnimator.setInterpolator(new LinearInterpolator());    valueAnimator.setDuration(30 * value);    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @Override      public void onAnimationUpdate(ValueAnimator animation) {        curValue = (int) animation.getAnimatedValue();        Log.i("debug", "curValue=" + curValue);        invalidate();      }    });    valueAnimator.addListener(new AnimatorListenerAdapter() {      @Override      public void onAnimationEnd(Animator animation) {        super.onAnimationEnd(animation);        isAnimEnd = true; //標記動畫結束        Log.i("debug", "onAnimationEnd");        Log.i("debug", "onAnimationEnd curValue = " + curValue);        invalidate();      }    });    valueAnimator.start();  }}

以上所述是小編給大家介紹的Android自定義View實現仿駕考寶典顯示分數效果(收藏),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VEVB武林網網站的支持!


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 金阳县| 织金县| 青阳县| 怀化市| 永顺县| 彝良县| 正阳县| 绵阳市| 清河县| 塔河县| 嘉定区| 大同县| 彩票| 武邑县| 隆子县| 陆河县| 嫩江县| 文山县| 五峰| 建宁县| 朝阳县| 毕节市| 晋宁县| 邯郸市| 武邑县| 衡水市| 兰西县| 中阳县| 汉中市| 聂荣县| 德庆县| 于都县| 肇东市| 灯塔市| 靖安县| 康定县| 民乐县| 财经| 徐汇区| 永胜县| 广州市|