Snake
Snake

Reputation: 14678

Circular progress bar, how to achieve this

I am trying to do a circular progress bar where the progress bar consists of solid color and a red dot. See the image below. Basically it is a timer where the red dot "eats" the white color. This is what I am trying to achieve:

enter image description here

Here is the code that I am using from other StackOverflow questions

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="270"
    android:toDegrees="270">
    <shape
        android:innerRadiusRatio="2.5"
        android:shape="ring"
        android:thickness="1dp"
        android:useLevel="true">

        <gradient
            android:angle="0"
            android:endColor="#FFFFFF"
            android:startColor="#FFFFFF"
            android:type="sweep"
            android:useLevel="false" />
    </shape>
</rotate>

With this code I can get the white ring but how can I get the red dot moving with it (using XML)

Thank you

PS: This is not a duplicate question as I didn't see a question that discusses progress bar having 2 different types of drawables.

Upvotes: 2

Views: 621

Answers (2)

Amrdroid
Amrdroid

Reputation: 387

you can create custom Progress View by Extends View Class and override onDraw() method to draw semi circle you can use drawArc()

and use ValueAnimator to change angle of Arc

Code:

TimerView.java 

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.support.v4.math.MathUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;

import java.util.concurrent.TimeUnit;

public class TimerView extends View {
private Paint ProgressPaint,indicatorPaint;
private float mProgressValue;
private ValueAnimator mTimerAnimator;
float stratAngel=270;
private int strokeWidth=10;

public TimerView(Context context) {
    super(context);
    ini();
}

public TimerView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    ini();

}

public TimerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    ini();

}

void ini(){
    ProgressPaint =new Paint();
    ProgressPaint.setAntiAlias(true);
    ProgressPaint.setStyle(Paint.Style.STROKE);
    ProgressPaint.setStrokeWidth(strokeWidth);
    ProgressPaint.setColor(Color.WHITE);

    indicatorPaint=new Paint();
    indicatorPaint.setAntiAlias(true);
    indicatorPaint.setStyle(Paint.Style.FILL);
    indicatorPaint.setColor(Color.RED);



}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    float w = (getWidth() - getPaddingLeft() - getPaddingRight())/2;
    float h = (getHeight() - getPaddingTop() - getPaddingBottom())/2;
    float radius = Math.min(w, h) / 2.0f;

    PointF center = new PointF(getLeft() + radius, getTop() + radius);

   RectF rect = new RectF(center.x - radius, center.y - radius,
           center.x + radius, center.y + radius);
    float progressAngel=360 * mProgressValue;
    canvas.drawArc(rect, stratAngel, progressAngel, false, ProgressPaint);
    float xPos = radius * (float)Math.cos(Math.toRadians(stratAngel+progressAngel)) + center.x;
    float yPos = radius * (float)Math.sin(Math.toRadians(stratAngel+progressAngel)) + center.y;
    canvas.drawCircle(xPos, yPos, 30, indicatorPaint);


}


public void start(int secs) {
    stop();

    mTimerAnimator = ValueAnimator.ofFloat(1f, 0f);
    mTimerAnimator.setDuration(TimeUnit.SECONDS.toMillis(secs));
    mTimerAnimator.setInterpolator(new LinearInterpolator());
    mTimerAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mProgressValue=(float) animation.getAnimatedValue();
            invalidate();
        }
    });
    mTimerAnimator.setRepeatCount(Integer.MAX_VALUE);
    mTimerAnimator.start();
}

public void stop() {
    if (mTimerAnimator != null && mTimerAnimator.isRunning()) {
        mTimerAnimator.cancel();
        mTimerAnimator = null;
        mProgressValue=0.0f;

    }
}


@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    start(5);
}




 }

and use it in xml layout like that:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="#dedede"
android:padding="16dp"
>
<<your package name>.TimerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />
 </LinearLayout>

final Result :screenshot

hope it Helps

Upvotes: 1

Amir Mohsenian
Amir Mohsenian

Reputation: 94

You should use progress bar. Add progress bar view to your code then add background XML file like below code :

 <?xml version="1.0" encoding="UTF-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromDegrees="120"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="140">
        <item android:id="@android:id/background">
            <shape
                android:innerRadiusRatio="2.6"
                android:shape="ring"
                android:useLevel="false"
                android:angle="0"
                android:type="sweep"
                android:thicknessRatio="80.0">
                <solid android:color="#d3d3d3"/>
            </shape>
        </item>
        <item android:id="@+id/rate_progress">
            <rotate
                android:fromDegrees="270"
                android:toDegrees="270">
                <shape
                    android:innerRadiusRatio="2.78"
                    android:shape="ring"
                    android:angle="0"
                    android:type="sweep"
                    android:thicknessRatio="15.0">
                    <solid android:color="@color/colorAccent"/>
                </shape>
            </rotate>
        </item>
    </layer-list>

set below background to your progress bar . below code is my example :

LayerDrawable layerDrawable = (LayerDrawable) progressBar.getContext().getResources()
            .getDrawable(R.drawable.rate_background);
    RotateDrawable progressDrawable = (RotateDrawable) layerDrawable
            .findDrawableByLayerId(R.id.rate_progress);
    GradientDrawable gradientDrawable = (GradientDrawable) progressDrawable.getDrawable();
    if (gradientDrawable != null) {
        gradientDrawable.setColor(Color.parseColor(color));
        progressBar.setProgressDrawable(layerDrawable);
    }
    progressBar.setProgress(rate);

And add below style to your progress bar

 style="?android:attr/progressBarStyleHorizontal"

Upvotes: 1

Related Questions