How to draw a circle with animation in android with circle size based on a value

前端 未结 3 1961
眼角桃花
眼角桃花 2020-11-29 16:42

I want to develop a custom component which draws part of the circle based on different values. e.g draw 1/4 cirle, 1/2 circle etc. The component needs to be animated to disp

相关标签:
3条回答
  • 2020-11-29 17:02

    You have to draw the circle view, and after that you should create an animation to it.

    Creating the circle view:

    public class Circle extends View {
    
        private static final int START_ANGLE_POINT = 90;
    
        private final Paint paint;
        private final RectF rect;
    
        private float angle;
    
        public Circle(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            final int strokeWidth = 40;
    
            paint = new Paint();
            paint.setAntiAlias(true);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(strokeWidth);
            //Circle color
            paint.setColor(Color.RED);
    
            //size 200x200 example
            rect = new RectF(strokeWidth, strokeWidth, 200 + strokeWidth, 200 + strokeWidth);
    
            //Initial Angle (optional, it can be zero)
            angle = 120;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint);
        }
    
        public float getAngle() {
            return angle;
        }
    
        public void setAngle(float angle) {
            this.angle = angle;
        }
    }
    

    Creating the animation class to set the new angle:

    public class CircleAngleAnimation extends Animation {
    
        private Circle circle;
    
        private float oldAngle;
        private float newAngle;
    
        public CircleAngleAnimation(Circle circle, int newAngle) {
            this.oldAngle = circle.getAngle();
            this.newAngle = newAngle;
            this.circle = circle;
        }
    
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation transformation) {
            float angle = oldAngle + ((newAngle - oldAngle) * interpolatedTime);
    
            circle.setAngle(angle);
            circle.requestLayout();
        }
    }
    

    Put circle into your layout:

    <com.package.Circle
        android:id="@+id/circle"
        android:layout_width="300dp"
        android:layout_height="300dp" />
    

    And finally starting the animation:

    Circle circle = (Circle) findViewById(R.id.circle);
    
    CircleAngleAnimation animation = new CircleAngleAnimation(circle, 240);
    animation.setDuration(1000);
    circle.startAnimation(animation);
    

    The result is: enter image description here

    0 讨论(0)
  • 2020-11-29 17:11

    As extra from @JohnCordeiro answer. I have added parameters from xml to reuse the circle and to fill the circle if needed.

    class RecordingCircle(context: Context, attrs: AttributeSet) : View(context, attrs) {
    
    private val paint: Paint
    private val rect: RectF
    
    private val fillPaint: Paint
    private val fillRect: RectF
    
    var angle: Float
    var startAngle: Float
    
    init {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RecordingCircle)
        startAngle = typedArray.getFloat(R.styleable.RecordingCircle_startAngle, 0f)
        val offsetAngle = typedArray.getFloat(R.styleable.RecordingCircle_offsetAngle, 0f)
        val color = typedArray.getColor(R.styleable.RecordingCircle_color, ResourcesCompat.getColor(resources, R.color.recording, null))
        val strokeWidth = typedArray.getFloat(R.styleable.RecordingCircle_strokeWidth, 20f)
        val circleSize = typedArray.getDimension(R.styleable.RecordingCircle_cicleSize, 100f)
        val fillColor = typedArray.getColor(R.styleable.RecordingCircle_fillColor, 0)
        typedArray.recycle()
    
        paint = Paint().apply {
            setAntiAlias(true)
            setStyle(Paint.Style.STROKE)
            setStrokeWidth(strokeWidth)
            setColor(color)
        }
    
        rect = RectF(
            strokeWidth,
            strokeWidth,
            (circleSize - strokeWidth),
            (circleSize - strokeWidth)
        )
    
        fillPaint = Paint().apply {
            setAntiAlias(true)
            setStyle(Paint.Style.FILL)
            setColor(fillColor)
        }
    
        val offsetFill = strokeWidth
        fillRect = RectF(
            offsetFill,
            offsetFill,
            (circleSize - offsetFill),
            (circleSize - offsetFill)
        )
    
        //Initial Angle (optional, it can be zero)
        angle = offsetAngle
    }
    
    override protected fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (fillColor > 0) {
            canvas.drawArc(rect, 0f, 360f, false, fillPaint)
        }
        canvas.drawArc(rect, startAngle, angle, false, paint)
    }
    }
    

    And on the xml:

            <com.myapp.RecordingCircle android:id="@+id/cameraRecordButton"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:offsetAngle="360"
            app:color="@color/light_grey"
            app:strokeWidth="10"
            app:cicleSize="@dimen/camera_record_button"
            app:fillColor="@color/recording_bg" />
    
        <com.myapp.RecordingCircle android:id="@+id/progress"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:startAngle="270"
            app:color="@color/recording"
            app:strokeWidth="10"
            app:cicleSize="@dimen/camera_record_button" />
    

    Here the result: Note the semi-transparent fill of the button

    0 讨论(0)
  • 2020-11-29 17:26

    Added code for calculating correct circle measurements

    import android.content.Context
    import android.graphics.Canvas
    import android.graphics.Color
    import android.graphics.Paint
    import android.graphics.RectF
    import android.util.AttributeSet
    import android.view.View
    import androidx.core.content.ContextCompat
    
    class Circle(context: Context, attrs: AttributeSet) : View(context, attrs) {
    
        private val paint: Paint
        private val rect: RectF
    
        var angle = 0f
    
        companion object {
            private val START_ANGLE_POINT = 270f
        }
    
        init {
            val strokeWidth = resources.getDimension(R.dimen.toast_circle_stroke_width)
    
            paint = Paint().apply {
                setAntiAlias(true)
                setStyle(Paint.Style.STROKE)
                setStrokeWidth(strokeWidth)
                setColor(Color.RED)
            }
    
            val circleSize = resources.getDimension(R.dimen.toast_circle_size)
    
            rect = RectF(
                strokeWidth,
                strokeWidth,
                circleSize + strokeWidth,
                circleSize + strokeWidth
            )
        }
    
        override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
            val circleSize = resources.getDimension(R.dimen.toast_circle_size).toInt()
            val strokeWidth = resources.getDimension(R.dimen.toast_circle_stroke_width).toInt()
    
            super.onMeasure(
                MeasureSpec.makeMeasureSpec(circleSize + 2 * strokeWidth, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(circleSize + 2 * strokeWidth, MeasureSpec.EXACTLY));
        }
    
        override fun onDraw(canvas: Canvas) {
            super.onDraw(canvas)
            canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint)
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题