In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces how to use Android to achieve arc refresh animation, the article is very detailed, has a certain reference value, interested friends must read it!
The effect of the animation is that three arcs are rotated, and the radians are gradually increasing and shrinking, which is used to draw three arcs in onDraw.
/ / draw arcs mPaint.setColor (mTopColor); canvas.drawArc (left, top, right, bottom, startAngle, sweepAngle, false, mPaint); mPaint.setColor (mLeftColor); canvas.drawArc (left, top, right, bottom, startAngle-120, sweepAngle, false, mPaint); mPaint.setColor (mRightColor); canvas.drawArc (left, top, right, bottom, startAngle + 120sweepAngle, false, mPaint)
The animation is based on drawing arcs of three different colors in turn in onDraw. The three arcs are often separated by 120 degrees, so that the whole circle can be evenly divided, which is more beautiful.
Notice that the initial value of startAngle here is-90, which is exactly the top point of the circle. It should be noted that in canvas's drawArc method, the first four parameters are the coordinates of the rectangle that determines the position of the arc, startAngle refers to the angle at which the arc begins, 0 degree is the rightmost point of the circle, and clockwise is positive and counterclockwise is negative. So-90 degrees happens to be the top point of the circle.
SweepAngle refers to the angle at which the arc is swept, also positive clockwise and negative counterclockwise. Here the initial size of the sweepAngle is-1, so that a dot can be drawn before the animation starts (actually an arc with an angle of 1, an approximate dot). The latter parameter is useCenter, which refers to whether to use the center. If it is true, it will connect the two ends of the arc to the center of the circle to form a sector, and if it is false, it will not connect the center of the circle.
Also note that the style of paint should be set to stroke, which is fill mode by default, that is, it will be populated directly. For the arc here, the two ends of the arc are directly connected to form a closed shape and then filled.
In this way, the initial state of the animation is drawn: three dots (actually an arc with an angle of 1).
It can also be seen from the above that there must be four coordinates to draw an arc, and the coordinates here are obtained in this way: the shortest side of the length and width of the View is taken as the side length of the square that makes up the circle, and then displayed in the center.
Int width = getMeasuredWidth (); int height = getMeasuredHeight (); int side = Math.min (width-getPaddingStart ()-getPaddingEnd (), height-getPaddingTop ()-getPaddingBottom ())-(int) (mStrokeWidth + 0.5F); / / determine the animation position float left = (width-side) / 2F = height-side / 2F = left + side;float bottom = top + side
The above code is the implementation of locating the square coordinates of the arc. Here you can see that the padding and mStrokenWidth of view are removed when calculating the side length side. Where mStrokenWidth is the width of the arc, because when the arc is wide (which is equivalent to the ring at this time), it will extend evenly inside and outside, that is, the distance from the middle of the inner margin and the outer margin to the center of the circle is the radius. Therefore, when determining the location of the arc, the lineweight should be removed to prevent the arc from being fully drawn at the junction.
In addition, when we customize View, the default wrap_content mode will have the same effect as match_parent, so it needs to be handled in onMeasure. Here, simply set it to 20dp in wrap_content mode.
@ Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure (widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode (widthMeasureSpec); int heightMode = MeasureSpec.getMode (heightMeasureSpec); int width = MeasureSpec.getSize (widthMeasureSpec); int height = MeasureSpec.getSize (heightMeasureSpec); / / for wrap_content, set it to 20dp. By default, wrap_content and match_parent have the same effect if (widthMode = = MeasureSpec.AT_MOST) {width = (int) (TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_DIP, 20, getContext (). GetResources (). GetDisplayMetrics ()) + 0.5F);} if (heightMode = = MeasureSpec.AT_MOST) {height = (int) (TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_DIP, 20, getContext (). GetResources (). GetDisplayMetrics ()) + 0.5F);} setMeasuredDimension (width, height) }
The above operation is the whole foundation of the animation, and the operation to get View moving is to constantly modify the arc's startAngle and sweepAngle, and then trigger the redrawing of View. This process uses ValueAnimator to generate a series of numbers, and then use this to calculate the starting angle and scanning angle of the arc.
/ / the minimum angle is 1 degree, which is used to display the dot sweepAngle =-1 position startAngle = 90 position curStartAngle = startAngle;// extended animation mValueAnimator = ValueAnimator.ofFloat (0,1) .setDuration (mDuration); mValueAnimator.setRepeatMode (ValueAnimator.REVERSE); mValueAnimator.setRepeatCount (ValueAnimator.INFINITE); mValueAnimator.addUpdateListener (animation-> {float fraction = animation.getAnimatedFraction (); float value = (float) animation.getAnimatedValue (); if (mReverse) fraction = 1-fraction; startAngle = curStartAngle + fraction * 120; sweepAngle =-1-mMaxSweepAngle * value) PostInvalidate (); mValueAnimator.addListener (new AnimatorListenerAdapter () {@ Override public void onAnimationRepeat (Animator animation) {curStartAngle = startAngle; mReverse =! mReverse;}})
The above is the process of calculation, the animation uses the value value from 0 to 1 and then to 0, corresponding to one of the arcs extend from the origin to the maximum and then shrink back to the origin. The calculation of sweepAngle is sweepAngle =-1-mMaxSweepAngle * value, that is, in the whole process, the angle of the arc gradually increases to maxSweepAngle. Negative values are used here, that is, drawing counterclockwise from startAngle. -1 is the base value to prevent it from shrinking to a minimum and showing a dot.
StartAngle is calculated based on the fraction of the animation process, rather than the animation value, that is, from 0 to 1, gradually increasing by 120 degrees throughout the animation process. Because the whole View is formed by three identical arcs, that is, each arc can only occupy a maximum of 120 degrees, otherwise it will overlap. So in the process of 0 to 1, the Radian increases to 120 degrees, and the startAngle must move 120 degrees to make room for the arc. This is the origin of 120 degrees. And monitor the Reverse state, because in the Reverse state, the fraction is from 1 to 0, and what we need is that the startAngle has been growing gradually, so we use 1-fraction to make it consistent with the original animation in Reverse. And each time reverse listens, record startAngle as the new current location and record reverse status.
These are the details of the whole arc animation, which is relatively simple as a whole, that is, by changing the startAngle and sweepAngle of the Radian and then informing View to redraw. The following is the complete code for the implementation, where some basic variables are extracted and put into properties to easily control the display of the animation:
Values/attrs.xml
RefreshView.java
Package com.pgaofeng.mytest.other;import android.animation.Animator;import android.animation.AnimatorListenerAdapter;import android.animation.ValueAnimator;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.util.TypedValue;import android.view.View;import com.pgaofeng.mytest.R / * * @ author gaofengpeng * @ date 2019-9-16 * @ description: * / public class RefreshView extends View {/ * three colors of the animation * / private int mTopColor; private int mLeftColor; private int mRightColor; private Paint mPaint; / * scan angle, which is used to control the length of the arc * / private float sweepAngle / * start angle, used to control the display position of the arc * / private float startAngle; / * current angle, record the angle of arc rotation * / private float curStartAngle; / * use animation to control the arc display * / private ValueAnimator mValueAnimator; / * the length of each cycle * / private int mDuration / * Arc lineweight * / private float mStrokeWidth; / * whether the maximum arc angle in the animation process * / private int mMaxSweepAngle; / * * automatically turns on the animation * / private boolean mAutoStart; / * is used to determine whether the current animation is in Reverse state * / private boolean mReverse = false; public RefreshView (Context context) {this (context, null) } public RefreshView (Context context, @ Nullable AttributeSet attrs) {this (context, attrs, 0);} public RefreshView (Context context, @ Nullable AttributeSet attrs, int defStyleAttr) {super (context, attrs, defStyleAttr); initAttr (context, attrs); init ();} private void initAttr (Context context, AttributeSet attrs) {TypedArray array = context.obtainStyledAttributes (attrs, R.styleable.RefreshView); mTopColor = array.getColor (R.styleable.RefreshView_top_color, Color.BLUE) MLeftColor = array.getColor (R.styleable.RefreshView_left_color, Color.YELLOW); mRightColor = array.getColor (R.styleable.RefreshView_right_color, Color.RED); mDuration = array.getInt (R.styleable.RefreshView_duration, 600); if (mDuration {float fraction = animation.getAnimatedFraction (); float value = (float) animation.getAnimatedValue (); if (mReverse) fraction = 1-fraction; startAngle = curStartAngle + fraction * 120 SweepAngle =-1-mMaxSweepAngle * value; postInvalidate (); mValueAnimator.addListener (new AnimatorListenerAdapter () {@ Override public void onAnimationRepeat (Animator animation) {curStartAngle = startAngle; mReverse =! mReverse;}});} @ Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure (widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode (widthMeasureSpec); int heightMode = MeasureSpec.getMode (heightMeasureSpec) Int width = MeasureSpec.getSize (widthMeasureSpec); int height = MeasureSpec.getSize (heightMeasureSpec); / / for wrap_content, set it to 20dp. By default, wrap_content and match_parent have the same effect if (widthMode = = MeasureSpec.AT_MOST) {width = (int) (TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_DIP, 20, getContext (). GetResources (). GetDisplayMetrics ()) + 0.5F) } if (heightMode = = MeasureSpec.AT_MOST) {height = (int) (TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_DIP, 20, getContext (). GetResources (). GetDisplayMetrics ()) + 0.5F);} setMeasuredDimension (width, height);} @ Override protected void onDraw (Canvas canvas) {super.onDraw (canvas); int width = getMeasuredWidth (); int height = getMeasuredHeight () Int side = Math.min (width-getPaddingStart ()-getPaddingEnd (), height-getPaddingTop ()-getPaddingBottom ())-(int) (mStrokeWidth + 0.5F); / / determine the animation position float left = (width-side) / 2F; float top = (height-side) / 2F; float right = left + side; float bottom = top + side; / / draw the arc mPaint.setColor (mTopColor) Canvas.drawArc (left, top, right, bottom, startAngle, sweepAngle, false, mPaint); mPaint.setColor (mLeftColor); canvas.drawArc (left, top, right, bottom, startAngle-120,sweepAngle, false, mPaint); mPaint.setColor (mRightColor); canvas.drawArc (left, top, right, bottom, startAngle + 120,sweepAngle, false, mPaint);} @ Override protected void onDetachedFromWindow () {if (mAutoStart & mValueAnimator.isRunning ()) {mValueAnimator.cancel () } super.onDetachedFromWindow ();} @ Override protected void onAttachedToWindow () {if (mAutoStart & &! mValueAnimator.isRunning ()) {mValueAnimator.start ();} super.onAttachedToWindow ();} / * start animation * / public void start () {if (! mValueAnimator.isStarted ()) {mValueAnimator.start () }} / * pause animation * / public void pause () {if (mValueAnimator.isRunning ()) {mValueAnimator.pause ();} / * continue animation * / public void resume () {if (mValueAnimator.isPaused ()) {mValueAnimator.resume () }} / * stop animation * / public void stop () {if (mValueAnimator.isStarted ()) {mReverse = false; mValueAnimator.end ();} these are all the contents of the article "how to use Android to achieve arc refresh animation". Thank you for reading! Hope to share the content to help you, more related knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.