使用自定義View繪製圓形進度條效果
阿新 • • 發佈:2018-11-23
首先自定義屬性 res - values - attrs(自己建立):
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyCicle"> <!--畫筆的寬度--> <attr name="progress_paint_width" format="dimension" /> <!--畫筆顏色--> <attr name="progress_paint_color" format="color" /> <!--字型顏色--> <attr name="progress_text_color" format="color" /> <!--字型尺寸--> <attr name="progress_text_size" format="dimension" /> <!--載入進度的開始位置--> <attr name="location" format="enum"> <enum name="left" value="1" /> <enum name="top" value="2" /> <enum name="right" value="3" /> <enum name="bottom" value="4" /> </attr> </declare-styleable> </resources>
自定義佈局類:
/** * date:2018/11/22 * author:(家輝輝輝) * function:圓形進度條 * 思路: * 1.自定義屬性:文字的顏色和字型大小,圓弧的顏色和寬度,一開始載入進度的位置; * 2.畫出需要的效果:畫圓弧,畫字型,使用畫筆paint在canvas上繪製; * 3.設定進度,重新繪製; * 4.介面回撥。 * */ public class MyCicle extends View { private int mCurrent;//當前進度 private Paint mPaintOut; private Paint mPaintCurrent; private Paint mPaintText; private float mPaintWidth;//畫筆寬度 private int mPaintColor = Color.RED;//畫筆顏色 private int mTextColor = Color.BLACK;//字型顏色 private float mTextSize;//字型大小 private int location;//從哪個位置開始 private float startAngle;//開始角度 public MyCicle(Context context) { this(context,null); } public MyCicle(Context context,AttributeSet attrs) { this(context, attrs,0); } public MyCicle(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //初始化attrs.xml TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyCicle); location = array.getInt(R.styleable.MyCicle_location, 1); mPaintWidth = array.getDimension(R.styleable.MyCicle_progress_paint_width, dip2px(context, 4));//預設4dp mPaintColor = array.getColor(R.styleable.MyCicle_progress_paint_color, mPaintColor); mTextSize = array.getDimension(R.styleable.MyCicle_progress_text_size, dip2px(context, 18));//預設18sp mTextColor = array.getColor(R.styleable.MyCicle_progress_text_color, mTextColor); array.recycle(); //畫筆->背景圓弧 mPaintOut = new Paint(); mPaintOut.setAntiAlias(true); mPaintOut.setStrokeWidth(mPaintWidth); mPaintOut.setStyle(Paint.Style.STROKE); mPaintOut.setColor(Color.GRAY); mPaintOut.setStrokeCap(Paint.Cap.ROUND); //畫筆->進度圓弧 mPaintCurrent = new Paint(); mPaintCurrent.setAntiAlias(true); mPaintCurrent.setStrokeWidth(mPaintWidth); mPaintCurrent.setStyle(Paint.Style.STROKE); mPaintCurrent.setColor(mPaintColor); mPaintCurrent.setStrokeCap(Paint.Cap.ROUND); //畫筆->繪製字型 mPaintText = new Paint(); mPaintText.setAntiAlias(true); mPaintText.setStyle(Paint.Style.FILL); mPaintText.setColor(mTextColor); mPaintText.setTextSize(mTextSize); if (location == 1) {//預設從左側開始 startAngle = -180; } else if (location == 2) { startAngle = -90; } else if (location == 3) { startAngle = 0; } else if (location == 4) { startAngle = 90; } } /** * 根據手機的解析度從 dp 的單位 轉成為 px(畫素) * */ private float dip2px(Context context, int dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int size = width > height ? height : width; setMeasuredDimension(size, size); } @Override//繪製 protected void onDraw(Canvas canvas) { super.onDraw(canvas); //繪製背景圓弧,因為畫筆有一定的寬度,所有畫圓弧的範圍要比View本身的大小稍微小一些,不然畫筆畫出來的東西會顯示不完整 RectF rectF = new RectF(mPaintWidth / 2, mPaintWidth / 2, getWidth() - mPaintWidth / 2, getHeight() - mPaintWidth / 2); canvas.drawArc(rectF, 0, 360, false, mPaintOut); //繪製當前進度 float sweepAngle = 360 * mCurrent / 100; canvas.drawArc(rectF, startAngle, sweepAngle, false, mPaintCurrent); //繪製進度數字 String text = mCurrent + "%"; //獲取文字寬度 float textWidth = mPaintText.measureText(text, 0, text.length()); float dx = getWidth() / 2 - textWidth / 2; Paint.FontMetricsInt fontMetricsInt = mPaintText.getFontMetricsInt(); float dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom; float baseLine = getHeight() / 2 + dy; canvas.drawText(text, dx, baseLine, mPaintText); //判斷介面並呼叫介面 if (mLoadingCompleteListener != null && mCurrent == 100) { mLoadingCompleteListener.complete(); } } /** * 獲取當前進度值 * * @return */ public int getmCurrent() { return mCurrent; } /** * 設定當前進度並重新繪製介面 * * @param mCurrent */ public void setmCurrent(int mCurrent) { this.mCurrent = mCurrent; invalidate(); } //建立介面 public interface OnLoadingCompleteListener { void complete(); } //宣告介面 private OnLoadingCompleteListener mLoadingCompleteListener; //設定暴露方法 public void setOnLoadingCompleteListener(OnLoadingCompleteListener loadingCompleteListener) { this.mLoadingCompleteListener = loadingCompleteListener; } }
MainActicity佈局
<com.wjh.activity.myview.MyCicle android:id="@+id/mycicle" android:layout_width="150dp" android:layout_height="150dp" app:location="left" app:progress_paint_color="#10c4f1" app:progress_paint_width="4dp" app:progress_text_color="#3F51B5" app:progress_text_size="20sp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="55dp"/>
MainActivity程式碼:
public class MainActivity extends AppCompatActivity {
private MyCicle mMyCicle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//找控制元件
mMyCicle = findViewById(R.id.mycicle);
//進度條從0到100
ValueAnimator animator = ValueAnimator.ofFloat(0, 100);
animator.setDuration(4000);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float current = (float) animation.getAnimatedValue();
mMyCicle.setmCurrent((int) current);
}
});
animator.start();
//使用介面回撥
mMyCicle.setOnLoadingCompleteListener(new MyCicle.OnLoadingCompleteListener() {
@Override
public void complete() {
Toast.makeText(MainActivity.this, "載入完成", Toast.LENGTH_SHORT).show();
}
});
}
}