版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/darling_R/article/details/55002345
转载请注明出处:http://blog.csdn.net/darling_R/article/details/55002345
自定义view小练习:
自定义view,其实很简单,最关键的就是在设计和绘制上,看你想怎么设计,需要给用户提供什么属性,然后在onDraw()方法里利用画笔Paint在画布caves上会出来,只要你熟悉了caves以及paint的使用,相信绘制一个view对你来说就很简单了;
前面一片博客介绍了自定义view的入门,其步骤还是那几步:
1,在res/value下新建attrs.xml文件,定义一些需要暴露出来的属性
<resources>
<declare-styleable name="CircleProgressView">
<!-- 弧线宽度 -->
<attr name="arcWidth" format="dimension" />
<!-- 刻度个数 -->
<attr name="scaleCount" format="integer" />
<!-- 渐变起始颜色 -->
<attr name="startColor" format="color" />
<!-- 渐变终止颜色 -->
<attr name="endColor" format="color" />
<!-- 标签说明文本 -->
<attr name="labelText" format="string" />
<!-- 文本颜色 -->
<attr name="textColor" format="color" />
<!-- 百分比文本字体大小 -->
<attr name="progressTextSize" format="dimension" />
<!-- 标签说明字体大小 -->
<attr name="labelTextSize" format="dimension" />
</declare-styleable>
</resources>
2。新建CircleProgressView继承 View,重写三个构造方法,并且注意三个构造方法里的内容,需要初始化:
public CircleProgressView(Context context) {
this(context, null);
}
public CircleProgressView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
3。在第三个构造方法里获取自定义属性,并初始化需要的画笔
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressView, defStyleAttr, 0);
mArcWidth = a.getDimensionPixelSize(R.styleable.CircleProgressView_arcWidth, DensityUtils.dp2px(context, 5));
mScaleCount = a.getInt(R.styleable.CircleProgressView_scaleCount, 20);
mStartColor = a.getColor(R.styleable.CircleProgressView_startColor, 0xff3fc199);
mEndColor = a.getColor(R.styleable.CircleProgressView_endColor, 0xffFC3B07);
mColorArray = new int[]{mStartColor, mEndColor};
mLabeText = a.getString(R.styleable.CircleProgressView_labelText);
mTextColor = a.getColor(R.styleable.CircleProgressView_textColor, 0xff4f5f6f);
mProgressTextSize = a.getDimensionPixelSize(R.styleable.CircleProgressView_progressTextSize, DensityUtils.sp2px(context, 20));
mLabeTextSize = a.getDimensionPixelSize(R.styleable.CircleProgressView_labelTextSize, DensityUtils.sp2px(context, 18));
a.recycle();
mArcBackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿
// mArcBackPaint.setAntiAlias(true);//抗锯齿
mArcBackPaint.setStyle(Paint.Style.STROKE);//设置画笔是空心的
mArcBackPaint.setStrokeWidth(mArcWidth);//设置空心画笔画出来的边框宽度
mArcBackPaint.setColor(Color.LTGRAY);//设置画笔颜色
mArcForePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mArcForePaint.setStyle(Paint.Style.STROKE);
mArcForePaint.setStrokeWidth(mArcWidth);
mArcRectF = new RectF();
mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mLinePaint.setStyle(Paint.Style.STROKE);
mLinePaint.setColor(Color.WHITE);
mLinePaint.setStrokeWidth(DensityUtils.dp2px(context, 2));
mProgressTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mProgressTextPaint.setStyle(Paint.Style.FILL);//设置画笔是实心的
mProgressTextPaint.setColor(mTextColor);
mProgressTextPaint.setTextSize(mProgressTextSize);
mLabelTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mLabelTextPaint.setStyle(Paint.Style.FILL);
mLabelTextPaint.setColor(mTextColor);
mLabelTextPaint.setTextSize(mLabeTextSize);
mTextRect = new Rect();
4。重写onMesure,计算控件的宽高;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measuredDimension(widthMeasureSpec), measuredDimension(heightMeasureSpec));
}
private int measuredDimension(int measureSpec) {
int result;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
if (mode == MeasureSpec.EXACTLY) {//明确指定宽高
result = size;
} else {
result = 800;
if (mode == MeasureSpec.AT_MOST) {//一般为wrap_content;
result = Math.min(result, size);
}
}
return result;
}
5。重写onDraw,画出所需要的内容:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mArcRectF.set(mArcWidth / 2, mArcWidth / 2, getWidth() - mArcWidth / 2, getHeight() - mArcWidth / 2);
//画背景弧线
canvas.drawArc(mArcRectF, -90, 360, false, mArcBackPaint);
//设置渐变渲染
LinearGradient linearGradient = new LinearGradient(getWidth() / 2, 0, getWidth() / 2, getHeight(), mColorArray, null, Shader.TileMode.CLAMP);
mArcForePaint.setShader(linearGradient);
//画百分比值弧线
canvas.drawArc(mArcRectF, -90, mSweepAngle, false, mArcForePaint);
//画刻度线
for (int i = 0; i < mScaleCount; i++) {
canvas.drawLine(getWidth() / 2, 0, getWidth() / 2, mArcWidth, mLinePaint);
//旋转画布
canvas.rotate(360 / mScaleCount, getWidth() / 2, getHeight() / 2);
}
//画百分比文本
String progressText = mProgress + "%";
mProgressTextPaint.getTextBounds(progressText, 0, progressText.length(), mTextRect);
float progressTextWidth = mTextRect.width();
float progressTextHeight = mTextRect.height();
canvas.drawText(progressText, getWidth() / 2 - progressTextWidth / 2,
getHeight() / 2 + progressTextHeight / 2, mProgressTextPaint);
//画标签说明文本
mLabelTextPaint.getTextBounds(mLabeText, 0, mLabeText.length(), mTextRect);
canvas.drawText(mLabeText, getWidth() / 2 - mTextRect.width() / 2,
getHeight() / 2 - progressTextHeight / 2 - mTextRect.height(), mLabelTextPaint);
}
增加一个可供外部调用的方法,用来传入百分比数值;
/**
* 外部设置百分比方法
*
* @param progress
*/
public void setProgress(float progress) {
Log.e("--> ", progress + "");
ValueAnimator anim = ValueAnimator.ofFloat(mProgress, progress);
anim.setDuration((long) (Math.abs(mProgress - progress) * 20));
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mProgress = (float) animation.getAnimatedValue();
mSweepAngle = mProgress * 360 / 100;
mProgress = (float) (Math.round(mProgress * 10)) / 10;//四舍五入保留到小数点后两位
invalidate();
}
});
anim.start();
}
在布局文件里调用:
<com.yh.circleprogressview.CircleProgressView
android:id="@+id/circleProgressView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
app:arcWidth="5dp"
app:endColor="#FC3B07"
app:labelText="学习进度"
app:labelTextSize="18sp"
app:progressTextSize="20sp"
app:scaleCount="24"
app:startColor="#3B6BFA" />