English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
In the previous Android ultra-precise step counter development-In the home page of Dylan's step counter, a custom control is used, which is somewhat similar to the interface of QQ Movement, and there are also animation effects. Below, I will talk about how this View is drawn.
1.Let's first look at the effect diagram
2.Effect diagram analysis
Function description: The yellow represents the total planned exercise steps set by the user, and the red represents the current steps walked by the user.
Initial analysis: To customize a View and rewrite the onDraw() method to draw an arc.
3.Essential knowledge for drawing an arc
There is a method to draw an arc in Canvas
drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//Draw an arc
The first parameter is a RectF object, a rectangular area that defines the boundary of the ellipse for defining the shape, size, and arc,
The second parameter is the starting angle (degree) at the beginning of the arc, the starting angle of the arc, in degrees.
The third parameter is the angle swept by the arc, in the clockwise direction, in degrees, starting from zero degrees at the right center.
Parameter four, if it is true, the center of the circle will be included when drawing the arc, usually used to draw a sector; if it is false, this will be a curved line.
The fifth parameter is a Paint object;
For this method, you can take a look at the sketch I drew by hand, it's quite bad, just to express the meaning of these parameters and the drawing process. I apologize for the bad drawing!
4.Preparation for drawing
(1).Get the center point coordinates
/**The x coordinate of the center point*/ float centerX = (getWidth()) / 2;
(2).Establish a reference rectangle outside the arc
/**Specify the outer contour rectangle area of the arc*/ RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth);
5.The main steps of drawing
(1).【Step 1】Draw the overall yellow arc
/** * 1.Draw the yellow arc of the total steps * * @param canvas Brush * @param rectF Reference rectangle */ private void drawArcYellow(Canvas canvas, RectF rectF) { Paint paint = new Paint(); /** Default brush color, yellow */ paint.setColor(getResources().getColor(R.color.yellow)); /** The junction is an arc*/ paint.setStrokeJoin(Paint.Join.ROUND); /** Set the brush style Paint.Cap.Round, Cap.SQUARE, etc., to round and square respectively*/ paint.setStrokeCap(Paint.Cap.ROUND); /** Set the fill style of the pen Paint.Style.FILL : fill the inside;Paint.Style.FILL_AND_STROKE :fill the inside and stroke; Paint.Style.STROKE :only stroke*/ paint.setStyle(Paint.Style.STROKE); /**Anti-aliasing function*/ paint.setAntiAlias(true); /**Set the pen width*/ paint.setStrokeWidth(borderWidth); /**Method to draw an arc * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//Draw an arc The first parameter is a RectF object, a rectangular area that defines the boundary of the ellipse for defining the shape, size, and arc, The second parameter is the starting angle (degree) at the beginning of the arc, the starting angle of the arc, in degrees. The third parameter is the angle swept by the arc, in the clockwise direction, in degrees, starting from zero degrees at the right center. The fourth parameter is if it is true (true), the center of the circle will be included when drawing the arc, usually used to draw sector; if it is false (false), this will be an arc line, The fifth parameter is a Paint object; */ canvas.drawArc(rectF, startAngle, angleLength, false, paint); }
(2).【Step 2】Draw the red arc of the current progress
/** * 2Draw the red arc of the current step */ private void drawArcRed(Canvas canvas, RectF rectF) { Paint paintCurrent = new Paint(); paintCurrent.setStrokeJoin(Paint.Join.ROUND); paintCurrent.setStrokeCap(Paint.Cap.ROUND);//Radius of rounded corners paintCurrent.setStyle(Paint.Style.STROKE);//Set the fill style paintCurrent.setAntiAlias(true);//Anti-aliasing function paintCurrent.setStrokeWidth(borderWidth);//Set the pen width paintCurrent.setColor(getResources().getColor(R.color.red));//Set pen color canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent); }
(3).【Step 3】Draw the red number of the current progress
/** * 3Steps at the center of the ring */ private void drawTextNumber(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true);//Anti-aliasing function vTextPaint.setTextSize(numberTextSize); Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL); vTextPaint.setTypeface(font);//Font style 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).【Step 4】Draw the red number of 'steps'
/** * 4Text on the ring center [steps] */ private void drawTextStepString(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextSize(dipToPx(16)); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true);//Anti-aliasing function 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.How animation is implemented->ValueAnimator
ValueAnimator is the most core class in the entire property animation mechanism. The operation mechanism of property animation is realized by continuously operating on values, and the animation transition between the initial value and the final value is calculated by the ValueAnimator class. It uses a time loop mechanism internally to calculate the animation transition between values, and we only need to provide the initial value and final value to ValueAnimator, and tell it the duration of the animation, then ValueAnimator will automatically help us complete the smooth transition from the initial value to the final value.
/*Set animation for progress * @param start Initial value * @param current Final value * @param length Animation duration */ 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) { /**A smooth transition value generated between the initial value and the final value each time, gradually updating the progress*/ currentAngleLength = (float) animation.getAnimatedValue(); invalidate(); } }); progressAnimator.start(); }
7.The entire source code of the custom StepArcView
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. * The arc that displays the step number */ public class StepArcView extends View { /** * The width of the arc */ private float borderWidth = 38f; /** * Font size for drawing the step number */ private float numberTextSize = 0; /** * Step number */ private String stepNumber = "0"; /** * The angle at which the arc starts to be drawn */ private float startAngle = 135; /** * The angle between the angle corresponding to the end point and the angle corresponding to the starting point */ private float angleLength = 270; /** * The angle between the end point and the starting point of the red arc to be drawn for the current step */ private float currentAngleLength = 0; /** * Animation duration */ 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); /**The x coordinate of the center point*/ float centerX = (getWidth()) / 2; /**Specify the outer contour rectangle area of the arc*/ RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth); /**[Step 1] Draw the overall yellow arc*/ drawArcYellow(canvas, rectF); /**[Step 2] Draw the red arc of the current progress*/ drawArcRed(canvas, rectF); /**[Step 3] Draw the red number of the current progress*/ drawTextNumber(canvas, centerX); /**[Step 4] Draw the red number of 'steps'*/ drawTextStepString(canvas, centerX); } /** * 1.Draw the yellow arc of the total steps * * @param canvas Brush * @param rectF Reference rectangle */ private void drawArcYellow(Canvas canvas, RectF rectF) { Paint paint = new Paint(); /** Default brush color, yellow */ paint.setColor(getResources().getColor(R.color.yellow)); /** The junction is an arc*/ paint.setStrokeJoin(Paint.Join.ROUND); /** Set the brush style Paint.Cap.Round, Cap.SQUARE, etc., to round and square respectively*/ paint.setStrokeCap(Paint.Cap.ROUND); /** Set the fill style of the pen Paint.Style.FILL : fill the inside;Paint.Style.FILL_AND_STROKE :fill the inside and stroke; Paint.Style.STROKE :only stroke*/ paint.setStyle(Paint.Style.STROKE); /**Anti-aliasing function*/ paint.setAntiAlias(true); /**Set the pen width*/ paint.setStrokeWidth(borderWidth); /**Method to draw an arc * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//Draw an arc The first parameter is a RectF object, a rectangular area that defines the boundary of the ellipse for defining the shape, size, and arc, The second parameter is the starting angle (degree) at the beginning of the arc, the starting angle of the arc, in degrees. The third parameter is the angle swept by the arc, in the clockwise direction, in degrees, starting from zero degrees at the right center. The fourth parameter is if it is true (true), the center of the circle will be included when drawing the arc, usually used to draw sector; if it is false (false), this will be an arc line, The fifth parameter is a Paint object; */ canvas.drawArc(rectF, startAngle, angleLength, false, paint); } /** * 2Draw the red arc of the current step */ private void drawArcRed(Canvas canvas, RectF rectF) { Paint paintCurrent = new Paint(); paintCurrent.setStrokeJoin(Paint.Join.ROUND); paintCurrent.setStrokeCap(Paint.Cap.ROUND);//Radius of rounded corners paintCurrent.setStyle(Paint.Style.STROKE);//Set the fill style paintCurrent.setAntiAlias(true);//Anti-aliasing function paintCurrent.setStrokeWidth(borderWidth);//Set the pen width paintCurrent.setColor(getResources().getColor(R.color.red));//Set pen color canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent); } /** * 3Steps at the center of the ring */ private void drawTextNumber(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true);//Anti-aliasing function vTextPaint.setTextSize(numberTextSize); Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL); vTextPaint.setTypeface(font);//Font style 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); } /** * 4Text on the ring center [steps] */ private void drawTextStepString(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextSize(dipToPx(16)); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true);//Anti-aliasing function 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); } /** * Get the height of the number of the current step * * @param fontSize Font size * @return Font height */ 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(); } /** * dip to convert to 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)); } /** * The progress of steps taken * * @param totalStepNum The set number of steps * @param currentCounts The number of steps taken */ public void setCurrentCount(int totalStepNum, int currentCounts) { stepNumber = currentCounts + ""; setTextSize(currentCounts); /**If the number of steps taken currently exceeds the total number of steps, the arc is still270 degrees cannot be a garden*/ if (currentCounts > totalStepNum) { currentCounts = totalStepNum; } /**The percentage of steps taken out of the total number of steps*/ float scale = (float) currentCounts / totalStepNum; /**Convert to the length of the angle of the final angle to be reached-->arc length*/ float currentAngleLength = scale * angleLength; /**Start executing the animation*/ setAnimation(0, currentAngleLength, animationLength); } /** * Set animation for progress * ValueAnimator is the most core class in the entire property animation mechanism, and the operation mechanism of property animation is realized by continuously operating on values, * and the animation transition between the initial and final values is calculated by the ValueAnimator class. * it uses an internal time loop mechanism to calculate the animation transition between values, * We just need to provide the initial and final values to ValueAnimator and tell it the duration of the animation required, * Then ValueAnimator will automatically help us complete the smooth transition from the initial value to the final value. * * @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(); } /** * Set text size to prevent the font from being too large and not fitting after a particularly large step count, and dynamically set the font size * * @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.Usage Instructions
in 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" />
In Activity
StepArcView sv = (StepArcView) findViewById(R.id.sv); sv.setCurrentCount(7000, 1000);
The above-mentioned is the Android imitating QQ step count arc and animation effect introduced by the editor to everyone, hoping it will be helpful to everyone. If you have any questions, please leave a message, and the editor will reply to everyone in time. At the same time, I would also like to express my sincere gratitude to everyone for their support of the Yana tutorial website!
Statement: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been manually edited, and does not assume any relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#oldtoolbag.com (Please replace # with @ when sending an email to report abuse, and provide relevant evidence. Once verified, this site will immediately delete the content suspected of infringement.)