web-dev-qa-db-fra.com

Comment dessiner un cercle avec animation dans Android avec une taille de cercle basée sur une valeur

Je souhaite développer un composant personnalisé qui dessine une partie du cercle en fonction de différentes valeurs. dessinez par exemple 1/4 de cercle, 1/2 cercle, etc. Le composant doit être animé pour afficher le processus de dessin. Le cercle partiel est dessiné au-dessus d'une vue d'image statique et je prévois d'utiliser deux vues, l'une animée au-dessus de la vue statique. Toute suggestion comment développer cela?

Je mets la capture d'écran pour référence.

enter image description here

S'il vous plaît se référer à l'image, et avoir une idée de comment ça ressemble. Merci!

Merci d'avance.

56
Leon Li

Vous devez dessiner la vue circulaire, puis créer une animation.

Création de la vue circulaire:

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;
    }
}

Création de la classe d'animation pour définir le nouvel 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();
    }
}

Mettez un cercle dans votre mise en page:

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

Et enfin pour commencer l'animation:

Circle circle = (Circle) findViewById(R.id.circle);

CircleAngleAnimation animation = new CircleAngleAnimation(circle, 240);
animation.setDuration(1000);
circle.startAnimation(animation);

Le résultat est: enter image description here

137
John Cordeiro

En plus de @JohnCordeiro, répondez. J'ai ajouté des paramètres de xml pour réutiliser le cercle et pour remplir le cercle si nécessaire.

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)
}
}

Et sur le 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" />

Voici le résultat: Notez le remplissage semi-transparent du bouton

enter image description here

2
Sulfkain

Code ajouté pour le calcul des mesures de cercle correctes

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
palimad