Reputation: 14678
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:
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
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
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