文章目录
- 1、简介
- 2、步骤
- 2.1 先添加自定义的属性 attrs.xml
- 2.2 、编写自定义的 progress view CustomizeProgressBarView.java
- 2.3、布局文件 activity_main.xml
- 2.4、主文件 MainActivity .java
1、简介
就是自定义一个圆形进度条
2、步骤
文件结构:
2.1 先添加自定义的属性 attrs.xml
先在res\values目录下创建attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircularProgressView">
<attr name="ringWidth" format="dimension" />
<attr name="ringColor" format="color|reference" />
<attr name="progressTitle" format="string" />
</declare-styleable>
</resources>
2.2 、编写自定义的 progress view CustomizeProgressBarView.java
CustomizeProgressBarView.java
package com.example.myapplication;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
/**
* Circular progress view
*/
public class CustomizeProgressBarView extends View {
private String TAG = "CustomizeProgressBarView: ";
/**
* Factor to convert the factor to paint the arc.
* <p/>
* In this way the developer can use a more user-friendly [0..1f] progress
*/
public static final int PROGRESS_FACTOR = -360;
/**
* Property Progress of the outer circle.
* <p/>
* The progress of the circle. If is set
* to FALSE, this property will be used to indicate the completion of the outer circle [0..1f].
* <p/>
* If set to TRUE, the drawable will activate the loading mode, where the drawable will
* show a 90º arc which will be spinning around the outer circle as much as progress goes.
*/
public static final String PROGRESS_PROPERTY = "progress";
/**
* Rectangle where the filling ring will be drawn into.
*/
protected final RectF arcElements;
/**
* Width of the filling ring.
*/
protected int ringWidth;
/**
* Paint object to draw the element.
*/
protected final Paint paint;
/**
* Ring progress.
*/
protected float progress;
/**
* Color for the completed ring.
*/
protected int ringColor;
/**
* Ring progress title.
*/
protected String progressTitle;
/**
* default gradient color for the progress ring.
*/
private LinearGradient shader;
private Rect rec;
private AnimatorSet animation = null;
public CustomizeProgressBarView(Context context) {
this(context, null);
}
public CustomizeProgressBarView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.CircularProgressView);
ringColor = array.getColor(R.styleable.CircularProgressView_ringColor, 0);
ringWidth = (int) array.getDimension(R.styleable.CircularProgressView_ringWidth, 20);
progressTitle = array.getString(R.styleable.CircularProgressView_progressTitle);
array.recycle();
this.progress = 0;
this.paint = new Paint();
this.paint.setAntiAlias(true);
this.arcElements = new RectF();
rec = new Rect();
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Calculations on the different components sizes
int size = Math.min(canvas.getHeight(), canvas.getWidth());
float outerRadius = (size / 2) - (ringWidth / 2);
float offsetX = (canvas.getWidth() - outerRadius * 2) / 2;
float offsetY = (canvas.getHeight() - outerRadius * 2) / 2;
int halfRingWidth = ringWidth / 2;
float arcX0 = offsetX + halfRingWidth;
float arcY0 = offsetY + halfRingWidth;
float arcX = offsetX + outerRadius * 2 - halfRingWidth;
float arcY = offsetY + outerRadius * 2 - halfRingWidth;
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(ringWidth);
paint.setStrokeCap(Paint.Cap.ROUND);
arcElements.set(arcX0, arcY0, arcX, arcY);
paint.setColor(Color.GRAY);
canvas.drawArc(arcElements, 0, 360, false, paint);
if (ringColor != 0) {
paint.setColor(ringColor);
canvas.drawArc(arcElements, -90, -progress, false, paint);
} else {
if (shader == null) {
shader = new LinearGradient(0, offsetY, 0, offsetY + outerRadius * 2, new int[]{Color.parseColor("#B4ED50"),
Color.parseColor("#429321")},
null, Shader.TileMode.CLAMP);
}
paint.setShader(shader);
canvas.drawArc(arcElements, -90, -progress, false, paint);
}
int progressText = -(int) (progress / 3.6);
String v = progressText + "%";
paint.setShader(null);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLUE);
paint.setTextSize(spToPx(30));
paint.getTextBounds(v, 0, v.length(), rec);
int textwidth = rec.width();
int textheight = rec.height();
// draw the center words
if (progressTitle != null && !progressTitle.isEmpty()) {
canvas.drawText(v, (canvas.getWidth() - textwidth) / 2, (canvas.getHeight() + textheight) / 2 - dpToPx(20), paint);
paint.setTextSize(spToPx(16));
paint.getTextBounds(progressTitle, 0, progressTitle.length(), rec);
int textwidth1 = rec.width();
int textheight1 = rec.height();
canvas.drawText(progressTitle, (canvas.getWidth() - textwidth1) / 2, (canvas.getHeight() + textheight1) / 2 + dpToPx(20), paint);
} else {
canvas.drawText(v, (canvas.getWidth() - textwidth) / 2, (canvas.getHeight() + textheight) / 2, paint);
}
}
/**
* Change sp to px.
*
* @param sp the sp value.
* @return the px value.
*/
private float spToPx(int sp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getContext().getResources().getDisplayMetrics());
}
/**
* Change dp to px.
*
* @param dp the dp value.
* @return the px value.
*/
private float dpToPx(int dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics());
}
/**
* Returns the progress of the outer ring.
* <p/>
* Will output a correct value only when the indeterminate mode is set to FALSE.
*
* @return Progress of the outer ring.
*/
public float getProgress() {
return progress / PROGRESS_FACTOR;
}
/**
* Sets the progress [0..1f].
*
* @param progress Sets the progress.
*/
public void setProgress(float progress) {
this.progress = PROGRESS_FACTOR * progress / 100.0f;
Log.i(TAG,"progress " + this.progress);
if (this.progress < -360) {
this.progress = -360;
}
invalidate();
}
/**
* Gets the filled ring color.
*
* @return Returns the filled ring color.
*/
public int getRingColor() {
return ringColor;
}
/**
* Sets the progress ring color.
*
* @param ringColor Ring color in #AARRGGBB format.
*/
public void setRingColor(int ringColor) {
this.ringColor = ringColor;
invalidate();
}
/**
* Sets the ring width.
*
* @param ringWidth Default ring width.
*/
public void setRingWidth(int ringWidth) {
this.ringWidth = ringWidth;
invalidate();
}
/**
* Gets the ring width.
*
* @return Returns the ring width.
*/
public int getRingWidth() {
return ringWidth;
}
/**
* Sets the progress title.
*
* @param progressTitle Sets the progress.
*/
public void setProgressTitle(String progressTitle) {
this.progressTitle = progressTitle;
invalidate();
}
/**
* Start progress animation or show the progress directly.
*
* @param progress the progress you set.
* @param isAnim weather to show the animation.
*/
@SuppressLint("WrongConstant")
public void startAnim(float progress, boolean isAnim) {
animation = new AnimatorSet();
ObjectAnimator progressAnimation = ObjectAnimator.ofFloat(this, CustomizeProgressBarView.PROGRESS_PROPERTY,
0f, progress);
progressAnimation.setDuration(isAnim ? 1000*10 : 0);
progressAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
progressAnimation.setRepeatCount(ValueAnimator.INFINITE);//无限循环
progressAnimation.setRepeatMode(ValueAnimator.INFINITE);
//another kind of animation
// ObjectAnimator colorAnimator = ObjectAnimator.ofInt(drawable, CircularProgressDrawable.RING_COLOR_PROPERTY,
// getResources().getColor(android.R.color.holo_red_dark),
// getResources().getColor(android.R.color.holo_green_light));
// colorAnimator.setEvaluator(new ArgbEvaluator());
// colorAnimator.setDuration(3600);
// animation.playTogether(progressAnimation, colorAnimator);
animation.play(progressAnimation);
animation.start();
}
public void stopAnimation() {
Log.i(TAG,"stop animation");
animation.end();
}
}
2.3、布局文件 activity_main.xml
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.example.myapplication.CustomizeProgressBarView
android:layout_width="350dp"
android:layout_height="350dp"
android:id="@+id/progress_bar_id"
app:ringWidth = "20dp"
app:ringColor = "@color/colorAccent"
app:progressTitle ="Bar"/>
<Button
android:layout_width="300dp"
android:layout_height="50dp"
android:id="@+id/add_but_id"
android:text="add progress"/>
<Button
android:layout_width="300dp"
android:layout_height="50dp"
android:id="@+id/start_but_id"
android:text="start animation"/>
<Button
android:layout_width="300dp"
android:layout_height="50dp"
android:id="@+id/stop_but_id"
android:text="stop animation"/>
</LinearLayout>
2.4、主文件 MainActivity .java
MainActivity .java
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private String TAG = "MainActivity: ";
private Button mButtonAdd;
private Button mButtonStart;
private Button mButtonStop;
private float progress = 0f;
private CustomizeProgressBarView mCustomizeProgressBarView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCustomizeProgressBarView = findViewById(R.id.progress_bar_id);
mButtonAdd = findViewById(R.id.add_but_id);
mButtonStart = findViewById(R.id.start_but_id);
mButtonStop = findViewById(R.id.stop_but_id);
mButtonAdd.setOnClickListener(this);
mButtonStart.setOnClickListener(this);
mButtonStop.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.add_but_id:
progress = progress + 10f;
if (progress >= 100) {
progress = 0;
}
mCustomizeProgressBarView.setProgress(progress);
Log.i(TAG,"set progress " + progress);
break;
case R.id.start_but_id:
mCustomizeProgressBarView.startAnim(100f,true);
Log.i(TAG,"start animation");
break;
case R.id.stop_but_id:
mCustomizeProgressBarView.stopAnimation();
Log.i(TAG,"stop animation");
break;
}
}
}