自定義View是咱們做爲一個「猿」必要掌握的招數,下面介紹下招數。java
1.首先在onMeasure方法中量測量View和它的內容來肯定測量的寬度和高度。
onMeasure(int widthMeasureSpec, int heightMeasureSpec)android
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 獲取視圖寬高
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeight = MeasureSpec.getSize(heightMeasureSpec);
// 取最小值
if (mWidth != mHeight) {
int mMin = Math.min(mWidth, mHeight);
mWidth = mMin;
mHeight = mMin;
}
setMeasuredDimension(mWidth, mHeight);
}
2.在onDraw方法中獲得Canvas(畫布)繪製圖案
draw(Canvas canvas)web
獲得畫布後先用畫筆(Paint)畫出對應的圖案。canvas
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
drawConfig(canvas);// 初始設置
drawCircle(canvas);// 繪製圓
drawScaleLine(canvas);// 繪製刻度線
drawIndicator(canvas);// 繪製光標
drawTitleText(canvas);// 繪製標題文本
drawContentText(canvas);// 繪製內容文本
}
3.效果圖以下:
4.源碼以下:
/** * 做者:秦川小將 * 描述:CircleProgressView */
public class CircleProgressView extends View {
private Context mContext;
/** * 視圖寬高 */
private int mWidth, mHeight;
/** * 畫圓所在的距形區域 */
private RectF mRectF;
/** * 畫圓和刻度線 */
private Paint mPaint;
/** * 畫光標 */
private Paint mIndicatorPaint;
/** * 圓線條粗細 */
private int mStrokeWidth = 5;
/** * 進度圓線條粗細 */
private int mProgressLineWidth = 8;
/** * 刻度線粗細 */
private int mScaleLineWidth = 2;
/** * 進度 */
private float mProgress = 0;
/** * 進度最大值,默認100 */
private float mMaxProgress = 100;
/** * 線條顏色 */
private int mCircleLineColor;
/** * 進度條顏色 */
private int mCircleProgressLineColor;
/** * 圓弧線寬 */
private float mCircleBorderWidth;
/** * 內邊距 */
private float mCirclePadding;
/** * 標題文本 */
private String mTitleText;
/** * 內容文本 */
private String mContentText;
/** * 標題文本大小 */
private int mTitleTextSize;
/** * 內容文本大小 */
private int mContentTextSize;
/** * 標題字體顏色 */
private int mTitleTextColor;
/** * 內容字體顏色 */
private int mContentTextColor;
public CircleProgressView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
this.mContext = context;
mRectF = new RectF();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mIndicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
TypedArray mArray = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressView);
mCircleLineColor = mArray.getColor(R.styleable.CircleProgressView_circleLineColor, Color.parseColor("#D3D3D3"));
mCircleProgressLineColor = mArray.getColor(R.styleable.CircleProgressView_circleProgressLineColor, Color.parseColor("#FFFFFF"));
mCircleBorderWidth = mArray.getDimensionPixelSize(R.styleable.CircleProgressView_circleLineBorderWidth, dip2px(10));
mCirclePadding = mArray.getDimensionPixelSize(R.styleable.CircleProgressView_circleLinePadding, dip2px(5));
mTitleTextSize = mArray.getDimensionPixelSize(R.styleable.CircleProgressView_circleTitleTextSize, dip2px(20));
mContentTextSize = mArray.getDimensionPixelSize(R.styleable.CircleProgressView_circleContentTextSize, dip2px(20));
mTitleTextColor = mArray.getColor(R.styleable.CircleProgressView_circleTitleTextColor, Color.parseColor("#FFFFFF"));
mContentTextColor = mArray.getColor(R.styleable.CircleProgressView_circleContentTextColor, Color.parseColor("#FFFFFF"));
mArray.recycle();
}
/** * 設置最大值 * * @param maxProgress */
public void setMaxProgress(float maxProgress) {
this.mMaxProgress = maxProgress;
}
/** * 設置進度 * * @param progress 進度值 */
public void setProgress(float progress) {
this.mProgress = progress;
invalidate();
}
/** * 設置進度 * * @param progress 進度值 * @param duration 動畫時長 */
public void setProgress(float progress, long duration) {
setProgressAnimator(progress, duration);
}
/** * 設置進度動畫 * * @param progress 進度值 * @param duration 動畫持續時長 */
private void setProgressAnimator(float progress, long duration) {
float mDuration = ((mMaxProgress / duration) * progress) * 1000;
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, progress);
valueAnimator.setDuration((long) mDuration);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mProgress = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator.start();
}
/** * 設置進度條線條粗細 * * @param width */
public void setProgressLineWidth(int width) {
this.mProgressLineWidth = width;
}
/** * 設置刻度線線條粗細 * * @param width */
public void setScaleLineWidth(int width) {
this.mScaleLineWidth = width;
}
/** * 設置底圓線條顏色 * * @param color */
public void setCircleLineColor(int color) {
this.mCircleLineColor = color;
}
/** * 設置進度調線條顏色 * * @param color */
public void setCircleProgressLineColor(int color) {
this.mCircleProgressLineColor = color;
}
/** * 設置刻度線外邊距 * * @param width */
public void setCircleBorderWidth(float width) {
this.mCircleBorderWidth = width;
}
/** * 設置刻度線內邊距 * * @param padding */
public void setCirclePadding(float padding) {
this.mCirclePadding = padding;
}
/** * 設置標題 * * @param title */
public void setTitleText(String title) {
this.mTitleText = title;
}
/** * 設置標題字體顏色 * * @param color */
public void setTitleTextColor(int color) {
this.mTitleTextColor = color;
}
/** * 標題字體大小 * * @param size */
public void setTitleTextSize(int size) {
this.mTitleTextSize = size;
}
/** * 設置內容 * * @param content */
public void setContentText(String content) {
this.mContentText = content;
}
/** * 設置內容字體顏色 * * @param color */
public void setContentTextColor(int color) {
this.mContentTextColor = color;
}
/** * 內容字體大小 * * @param size */
public void setContentTextSize(int size) {
this.mContentTextSize = size;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 獲取視圖寬高
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeight = MeasureSpec.getSize(heightMeasureSpec);
// 取最小值
if (mWidth != mHeight) {
int mMin = Math.min(mWidth, mHeight);
mWidth = mMin;
mHeight = mMin;
}
setMeasuredDimension(mWidth, mHeight);
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
drawConfig(canvas);// 初始設置
drawCircle(canvas);// 繪製圓
drawScaleLine(canvas);// 繪製刻度線
drawIndicator(canvas);// 繪製光標
drawTitleText(canvas);// 繪製標題文本
drawContentText(canvas);// 繪製內容文本
}
/** * 初始設置 */
private void drawConfig(Canvas canvas) {
mPaint.setAntiAlias(true);// 是否抗鋸齒
canvas.drawColor(Color.TRANSPARENT); // 設置畫布爲透明
mPaint.setStyle(Paint.Style.STROKE);
// 位置
mRectF.left = 20; // 左上角X
mRectF.top = 20; // 左上角Y
mRectF.right = getWidth() - 20; // 右下角X
mRectF.bottom = getWidth() - 20; // 右下角Y
}
/** * 繪製圓 * * @param canvas */
private void drawCircle(Canvas canvas) {
canvas.save();
// 繪製底層圓
mPaint.setStrokeWidth(mStrokeWidth);
mPaint.setColor(mCircleLineColor);
canvas.drawArc(mRectF, -90, 360, false, mPaint);
// 繪製進度圓
mPaint.setStrokeWidth(mProgressLineWidth);
mPaint.setColor(mCircleProgressLineColor);
canvas.drawArc(mRectF, -90, (mProgress / mMaxProgress) * 360, false, mPaint);
canvas.restore();
}
/** * 繪製刻度線 * * @param canvas */
private void drawScaleLine(Canvas canvas) {
canvas.save();
//半徑
float mRadius = (getMeasuredWidth() - mCirclePadding * 3) / 2 - mCirclePadding;
//X軸中點座標
int mCenterX = getMeasuredWidth() / 2;
// 設置刻度線顏色
mPaint.setColor(mCircleLineColor);
mPaint.setStrokeWidth(mScaleLineWidth);
for (float i = 0; i < 360; i += 3.6) {
double mArc = i * Math.PI / 180;
float mStartX = (float) (mCenterX + (mRadius - mCircleBorderWidth) * Math.sin(mArc));
float mStartY = (float) (mCenterX + (mRadius - mCircleBorderWidth) * Math.cos(mArc));
float mStopX = (float) (mCenterX + mRadius * Math.sin(mArc) + 1);
float mStopY = (float) (mCenterX + mRadius * Math.cos(mArc) + 1);
canvas.drawLine(mStartX, mStartY, mStopX, mStopY, mPaint);
}
canvas.restore();
}
/** * 繪製光標 * * @param canvas */
private void drawIndicator(Canvas canvas) {
canvas.save();
float mRadius = getMeasuredWidth() / 2 - 20;
// 計算從正上方旋轉了多少度
float mArc = (mProgress / mMaxProgress) * 360;
// 計算圓弧上X,Y軸座標
float mIndicatorX = mRectF.centerX() + (float) (mRadius * Math.cos(Math.toRadians(mArc + 270)));
float mIndicatorY = mRectF.centerY() + (float) (mRadius * Math.sin(Math.toRadians(mArc + 270)));
// 設置相關屬性
mIndicatorPaint.setAntiAlias(true);
mIndicatorPaint.setStyle(Paint.Style.FILL);
mIndicatorPaint.setColor(mCircleProgressLineColor);
// 設置過濾器,設置模糊效果時需關閉硬件加速器
mIndicatorPaint.setMaskFilter(new BlurMaskFilter(dip2px(3), BlurMaskFilter.Blur.NORMAL));
canvas.drawCircle(mIndicatorX, mIndicatorY, dip2px(3), mIndicatorPaint);
canvas.restore();
}
/** * 繪製標題文本 * * @param canvas */
private void drawTitleText(Canvas canvas) {
if (!TextUtils.isEmpty(mTitleText)) {
canvas.save();
mPaint.setColor(mTitleTextColor);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTextSize(mTitleTextSize);
int mTextHeight = mHeight / 4;
int mTextWidth = (int) mPaint.measureText(mTitleText, 0, mTitleText.length());
canvas.drawText(mTitleText, (mWidth / 2) - (mTextWidth / 2), (mHeight / 3) + (mTextHeight / 2), mPaint);
canvas.restore();
}
}
/** * 繪製內容文本 * * @param canvas */
private void drawContentText(Canvas canvas) {
if (!TextUtils.isEmpty(mContentText)) {
canvas.save();
mPaint.setColor(mContentTextColor);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTextSize(mContentTextSize);
int mTextHeight = mHeight / 4;
int mTextWidth = (int) mPaint.measureText(mContentText, 0, mContentText.length());
canvas.drawText(mContentText, (mWidth / 2) - (mTextWidth / 2), ((mHeight / 4) + (mTextHeight / 2)) * 1.8F, mPaint);
canvas.restore();
}
}
public int dip2px(float dipValue) {
final float scale = mContext.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
}
3.自定義屬性:
<declare-styleable name="CircleProgressView">
<!--圓內刻度線寬度-->
<attr name="circleLineBorderWidth" format="reference|dimension|integer" />
<!--圓內刻度線內邊距-->
<attr name="circleLinePadding" format="reference|dimension|integer" />
<!--線條顏色-->
<attr name="circleLineColor" format="reference|color" />
<!--進度條線條顏色-->
<attr name="circleProgressLineColor" format="reference|color" />
<!--標題文本字體大小-->
<attr name="circleTitleTextSize" format="reference|dimension|integer" />
<!--內容文字大小-->
<attr name="circleContentTextSize" format="reference|dimension|integer" />
<!--標題文本字體顏色-->
<attr name="circleTitleTextColor" format="reference|color" />
<!--內容文本字體顏色-->
<attr name="circleContentTextColor" format="reference|color" />
</declare-styleable>
5.在佈局中使用
<!-- 這裏只對文本Size進行了設置,其餘屬性根據本身需求進行設置-->
<com.example.app.view.widget.CircleProgressView android:layout_width="200dp" android:layout_height="200dp" circle:circleContentTextSize="25sp" />
6.在java代碼中使用
mProgress.setTitleText("No.1");
mProgress.setContentText("Super VIP");
mProgress.setMaxProgress(100);
mProgress.setProgress(60, 3000);
本文分享 CSDN - 秦川小將。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。app