English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Nella homepage del contapassi ultra preciso per Android - Dylan Contapassi, è stato utilizzato un controllo personalizzato, simile all'interfaccia di QQ运动的,还有动画效果,下面就来讲解一下这个View是如何绘制的。
1. Prima di tutto, guardiamo l'effetto visivo
2. Analisi dell'effetto visivo
Descrizione delle funzioni: Giallo rappresenta il numero totale di passi di esercizio pianificato dall'utente, rosso rappresenta il numero di passi attualmente percorsi dall'utente.
初步分析:完全自定义View重写onDraw()方法,画圆弧。
3. 画一个圆弧必备知识
在Canvas中有一个画圆弧的方法
drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//画弧,
参数一是RectF对象,一个矩形区域椭圆形的界限用于定义在形状、大小、电弧,
参数二是起始角(度)在电弧的开始,圆弧起始角度,单位为度。
参数三圆弧扫过的角度,顺时针方向,单位为度,从右中间开始为零度。
参数四是如果是true(真)的话,在绘制圆弧时将圆心包括在内,通常用来绘制扇形;如果是false(假)这将是一个弧线。
参数五是Paint对象;
对于这个方法,大家可以看一下我手绘的草图,比较烂,表达一下这几个参数的意思和绘制过程,画得不好望大家见谅!
4. 绘图的准备工作
(1). 获取中心点坐标
/**中心点的x坐标*/ float centerX = (getWidth()) / 2;
(2). 建立一个圆弧外的参考矩形
/**指定圆弧的外轮廓矩形区域*/ RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth);
5. 主要的绘图步骤
(1).【第一步】绘制整体的黄色圆弧
/** * 1.绘制总步数的黄色圆弧 * * @param canvas 画笔 * @param rectF 参考的矩形 */ private void drawArcYellow(Canvas canvas, RectF rectF) { Paint paint = new Paint(); /** 默认画笔颜色,黄色 */ paint.setColor(getResources().getColor(R.color.yellow)); /** 结合处为圆弧*/ paint.setStrokeJoin(Paint.Join.ROUND); /** 设置画笔的样式 Paint.Cap.Round ,Cap.SQUARE等分别为圆形、方形*/ paint.setStrokeCap(Paint.Cap.ROUND); /** 设置画笔的填充样式 Paint.Style.FILL :填充内部;Paint.Style.FILL_AND_STROKE :填充内部和描边; Paint.Style.STROKE :仅描边*/ paint.setStyle(Paint.Style.STROKE); /**抗锯齿功能*/ paint.setAntiAlias(true); /**设置画笔宽度*/ paint.setStrokeWidth(borderWidth); /**绘制圆弧的方法 * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//画弧, 参数一是RectF对象,一个矩形区域椭圆形的界限用于定义在形状、大小、电弧, 参数二是起始角(度)在电弧的开始,圆弧起始角度,单位为度。 参数三圆弧扫过的角度,顺时针方向,单位为度,从右中间开始为零度。 参数四是如果这是true(真)的话,在绘制圆弧时将圆心包括在内,通常用来绘制扇形;如果它是false(假)这将是一个弧线, 参数五是Paint对象; */ canvas.drawArc(rectF, startAngle, angleLength, false, paint); }
(2).【第二步】绘制当前进度的红色圆弧
/** * 2.绘制当前步数的红色圆弧 */ private void drawArcRed(Canvas canvas, RectF rectF) { Paint paintCurrent = new Paint(); paintCurrent.setStrokeJoin(Paint.Join.ROUND); paintCurrent.setStrokeCap(Paint.Cap.ROUND);//圆角弧度 paintCurrent.setStyle(Paint.Style.STROKE);//设置填充样式 paintCurrent.setAntiAlias(true);//抗锯齿功能 paintCurrent.setStrokeWidth(borderWidth);//设置画笔宽度 paintCurrent.setColor(getResources().getColor(R.color.red));//设置画笔颜色 canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent); }
(3).【第三步】绘制当前进度的红色数字
/** * 3.环中心的步数 */ private void drawTextNumber(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true); // funzione anti-aliasing vTextPaint.setTextSize(numberTextSize); Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL); vTextPaint.setTypeface(font); // stile del carattere vTextPaint.setColor(getResources().getColor(R.color.red)); Rect bounds_Number = new Rect(); vTextPaint.getTextBounds(stepNumber, 0, stepNumber.length(), bounds_Number); canvas.drawText(stepNumber, centerX, getHeight() / 2 + bounds_Number.height() / 2, vTextPaint); }
(4).【第四步】绘制“步数”的红色数字
/** * 4. Testo al centro del cerchio [numero di passi] */ private void drawTextStepString(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextSize(dipToPx(16)); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true); // funzione anti-aliasing vTextPaint.setColor(getResources().getColor(R.color.grey)); String stepString = "步数"; Rect bounds = new Rect(); vTextPaint.getTextBounds(stepString, 0, stepString.length(), bounds); canvas.drawText(stepString, centerX, getHeight() / 2 + bounds.height() + getFontHeight(numberTextSize), vTextPaint); }
6. Come viene implementata l'animazione -> ValueAnimator
ValueAnimator è una delle classi più centrali del meccanismo di animazione delle proprietà, il funzionamento dell'animazione delle proprietà è realizzato通过对值进行 operazioni in continuo, e il passaggio di animazione tra il valore iniziale e il valore finale è responsabile da ValueAnimator questa classe calcolare. Internamente utilizza un meccanismo di ciclo temporale per calcolare la transizione tra valore e valore, è sufficiente fornire il valore iniziale e il valore finale a ValueAnimator e dirgli la durata dell'animazione, allora ValueAnimator ci aiuterà automaticamente a completare l'effetto di transizione fluida dal valore iniziale al valore finale.
/* Impostare l'animazione di progresso */ * @param start Valore iniziale * @param current Valore finale * @param length Durata dell'animazione */ private void setAnimation(float start, float current, int length) { ValueAnimator progressAnimator = ValueAnimator.ofFloat(start, current); progressAnimator.setDuration(length); progressAnimator.setTarget(currentAngleLength); progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { /** Ogni volta che si genera un valore di transizione fluido tra il valore iniziale e finale, che si aggiorna gradualmente il progresso */ currentAngleLength = (float) animation.getAnimatedValue(); invalidate(); } }); progressAnimator.start(); }
7. L'intero codice sorgente di StepArcView personalizzato
import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.util.AttributeSet; import android.view.View; import cn.bluemobi.dylan.step.R; /** * Created by DylanAndroid on 2016/5/26. * 显示步数的圆弧 */ public class StepArcView extends View { /** * 圆弧的宽度 */ private float borderWidth = 38f; /** * 画步数的数值的字体大小 */ private float numberTextSize = 0; /** * 步数 */ private String stepNumber = "0"; /** * 开始绘制圆弧的角度 */ private float startAngle = 135; /** * 终点对应的角度和起始点对应的角度的夹角 */ private float angleLength = 270; /** * 所要绘制的当前步数的红色圆弧终点到起点的夹角 */ private float currentAngleLength = 0; /** * 动画时长 */ private int animationLength = 3000; public StepArcView(Context context) { super(context); } public StepArcView(Context context, AttributeSet attrs) { super(context, attrs); } public StepArcView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); /**中心点的x坐标*/ float centerX = (getWidth()) / 2; /**指定圆弧的外轮廓矩形区域*/ RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth); /**【第一步】绘制整体的黄色圆弧*/ drawArcYellow(canvas, rectF); /**【第二步】绘制当前进度的红色圆弧*/ drawArcRed(canvas, rectF); /**【第三步】绘制当前进度的红色数字*/ drawTextNumber(canvas, centerX); /**【第四步】绘制"步数"的红色数字*/ drawTextStepString(canvas, centerX); } /** * 1.绘制总步数的黄色圆弧 * * @param canvas 画笔 * @param rectF 参考的矩形 */ private void drawArcYellow(Canvas canvas, RectF rectF) { Paint paint = new Paint(); /** 默认画笔颜色,黄色 */ paint.setColor(getResources().getColor(R.color.yellow)); /** 结合处为圆弧*/ paint.setStrokeJoin(Paint.Join.ROUND); /** 设置画笔的样式 Paint.Cap.Round ,Cap.SQUARE等分别为圆形、方形*/ paint.setStrokeCap(Paint.Cap.ROUND); /** 设置画笔的填充样式 Paint.Style.FILL :填充内部;Paint.Style.FILL_AND_STROKE :填充内部和描边; Paint.Style.STROKE :仅描边*/ paint.setStyle(Paint.Style.STROKE); /**抗锯齿功能*/ paint.setAntiAlias(true); /**设置画笔宽度*/ paint.setStrokeWidth(borderWidth); /**绘制圆弧的方法 * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//画弧, 参数一是RectF对象,一个矩形区域椭圆形的界限用于定义在形状、大小、电弧, 参数二是起始角(度)在电弧的开始,圆弧起始角度,单位为度。 参数三圆弧扫过的角度,顺时针方向,单位为度,从右中间开始为零度。 参数四是如果这是true(真)的话,在绘制圆弧时将圆心包括在内,通常用来绘制扇形;如果它是false(假)这将是一个弧线, 参数五是Paint对象; */ canvas.drawArc(rectF, startAngle, angleLength, false, paint); } /** * 2.绘制当前步数的红色圆弧 */ private void drawArcRed(Canvas canvas, RectF rectF) { Paint paintCurrent = new Paint(); paintCurrent.setStrokeJoin(Paint.Join.ROUND); paintCurrent.setStrokeCap(Paint.Cap.ROUND);//圆角弧度 paintCurrent.setStyle(Paint.Style.STROKE);//设置填充样式 paintCurrent.setAntiAlias(true);//抗锯齿功能 paintCurrent.setStrokeWidth(borderWidth);//设置画笔宽度 paintCurrent.setColor(getResources().getColor(R.color.red));//设置画笔颜色 canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent); } /** * 3.环中心的步数 */ private void drawTextNumber(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true); // funzione anti-aliasing vTextPaint.setTextSize(numberTextSize); Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL); vTextPaint.setTypeface(font); // stile del carattere vTextPaint.setColor(getResources().getColor(R.color.red)); Rect bounds_Number = new Rect(); vTextPaint.getTextBounds(stepNumber, 0, stepNumber.length(), bounds_Number); canvas.drawText(stepNumber, centerX, getHeight() / 2 + bounds_Number.height() / 2, vTextPaint); } /** * 4. Testo al centro del cerchio [numero di passi] */ private void drawTextStepString(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextSize(dipToPx(16)); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true); // funzione anti-aliasing vTextPaint.setColor(getResources().getColor(R.color.grey)); String stepString = "步数"; Rect bounds = new Rect(); vTextPaint.getTextBounds(stepString, 0, stepString.length(), bounds); canvas.drawText(stepString, centerX, getHeight() / 2 + bounds.height() + getFontHeight(numberTextSize), vTextPaint); } /** * Ottiene l'altezza del numero di passi corrente * * @param fontSize dimensione del carattere * @return altezza del carattere */ public int getFontHeight(float fontSize) { Paint paint = new Paint(); paint.setTextSize(fontSize); Rect bounds_Number = new Rect(); paint.getTextBounds(stepNumber, 0, stepNumber.length(), bounds_Number); return bounds_Number.height(); } /** * Convertire dip in px * * @param dip * @return */ private int dipToPx(float dip) { float density = getContext().getResources().getDisplayMetrics().density; return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1)); } /** * Progresso dei passi compiuti * * @param totalStepNum numero di passi impostato * @param currentCounts numero di passi compiuti */ public void setCurrentCount(int totalStepNum, int currentCounts) { stepNumber = currentCounts + ""; setTextSize(currentCounts); /**Se il numero di passi attuali supera il numero totale di passi, l'arco è ancora 270 gradi, non può diventare un cerchio*/ if (currentCounts > totalStepNum) { currentCounts = totalStepNum; } /**Percentuale di passi compiuti rispetto al numero totale di passi*/ float scale = (float) currentCounts / totalStepNum; /**Convertire la lunghezza dell'angolo finale in radianti in lunghezza arcuata*/ float currentAngleLength = scale * angleLength; /**Inizia l'esecuzione dell'animazione*/ setAnimation(0, currentAngleLength, animationLength); } /** * Animazione di progresso * ValueAnimator è una delle classi più fondamentali del meccanismo di animazione delle proprietà, il meccanismo di esecuzione dell'animazione delle proprietà viene realizzato attraverso operazioni continue sui valori; * e la transizione tra il valore iniziale e finale è responsabile della classe ValueAnimator. * utilizzando un meccanismo di ciclo temporale interno per calcolare la transizione tra i valori, * Dobbiamo solo fornire il valore iniziale e finale a ValueAnimator e dire quanto tempo deve durare l'animazione, * Quindi ValueAnimator ci aiuterà automaticamente a completare il passaggio fluido dall'iniziale al valore finale. * * @param last * @param current */ private void setAnimation(float last, float current, int length) { ValueAnimator progressAnimator = ValueAnimator.ofFloat(last, current); progressAnimator.setDuration(length); progressAnimator.setTarget(currentAngleLength); progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { currentAngleLength = (float) animation.getAnimatedValue(); invalidate(); } }); progressAnimator.start(); } /** * Imposta la dimensione del testo, per prevenire che il numero di passi sia particolarmente grande e non ci sia abbastanza spazio, impostare la dimensione del carattere dinamicamente * * @param num */ public void setTextSize(int num) { String s = String.valueOf(num); int length = s.length(); if (length <= 4) { numberTextSize = dipToPx(50); else if (length > 4 && length <= 6) { numberTextSize = dipToPx(40); } else if (length > 6 && length <= 8) { numberTextSize = dipToPx(30); } else if (length > 8) { numberTextSize = dipToPx(25); } } }
8. Descrizione dell'uso
nel xml
<cn.bluemobi.dylan.step.view.StepArcView android:id="@+id/sv " android:layout_width="200dp" android:layout_height="200dp" android:layout_centerHorizontal="true" android:layout_marginTop="50dp" />
Activity di
StepArcView sv = (StepArcView) findViewById(R.id.sv); sv.setCurrentCount(7000, 1000);
Quello che è stato descritto dall'editor in questo articolo è l'imitazione del contatore di passi circolare e dell'effetto animazione di QQ运动 per Android, speriamo che sia utile a tutti. Se avete qualsiasi domanda, lasciate un messaggio, l'editor risponderà tempestivamente. Inoltre, siamo molto grati per il supporto del sito Web di呐喊教程!
Dichiarazione: il contenuto di questo articolo è stato raccolto da Internet, è di proprietà dei rispettivi autori, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non detiene i diritti di proprietà, non è stato modificato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare, fornendo prove pertinenti. Una volta verificata, questo sito eliminerà immediatamente il contenuto sospetto di violazione del copyright.