項(xiàng)目年費(fèi)控件UI圖
image.png
實(shí)現(xiàn)效果
年費(fèi).gif
控件分析(從里到外進(jìn)行分析,最后分析指針)
1柄冲、中間有個(gè)紅色圓點(diǎn),抽取顏色和半徑
2忠蝗、白色圓環(huán)现横,抽取圓環(huán)寬度、圓環(huán)顏色
3阁最、包圍白色圓環(huán)的圓環(huán)寬度和顏色
4戒祠、指針指向的圓環(huán)顏色和寬度
5、進(jìn)度圓弧的寬度速种、顏色和底色
6姜盈、最外邊的圓弧顏色和寬度
7、指針顏色配阵、長(zhǎng)度和寬度
8贩据、進(jìn)度圓弧和最外層圓弧的距離
9、包圍白色圓環(huán)的圓環(huán)和指針指向的圓環(huán)距離
10闸餐、繪制進(jìn)度圓弧的開始角度為-225饱亮,掃描的最大度數(shù)為270
11、繪制指針時(shí)舍沙、先把畫布旋轉(zhuǎn)一定的角度再繪制
自定義屬性
<declare-styleable name="YearCostView">
<!--centerPoint-->
<attr name="center_point_color" format="color" />
<attr name="center_point_radius" format="dimension" />
<!--中間圓環(huán)的顏色和寬度-->
<attr name="center_ring_color" format="color" />
<attr name="center_ring_width" format="dimension" />
<!--包裹中心圓環(huán)的圓環(huán)-->
<attr name="wraper_center_ring_color" format="color" />
<attr name="wraper_center_ring_width" format="dimension" />
<!--指針-->
<attr name="line_width" format="dimension" />
<attr name="line_color" format="color" />
<!--inner圓環(huán)-->
<attr name="inner_ring_color" format="color" />
<attr name="inner_ring_width" format="dimension" />
<!--target圓環(huán)-->
<attr name="target_ring_color" format="color" />
<attr name="target_ring_width" format="dimension" />
<attr name="target_bottom_ring_color" format="color" />
<!--out圓環(huán)-->
<attr name="out_ring_color" format="color" />
<attr name="out_ring_width" format="dimension" />
<!--距離-->
<attr name="inner_distance" format="dimension" />
<attr name="out_distance" format="dimension" />
</declare-styleable>
獲取自定義屬性
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.YearCostView, defStyleAttr, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
//中心圓點(diǎn)
case R.styleable.YearCostView_center_point_radius:
centerPointRadius = a.getLayoutDimension(attr, centerPointRadius);
break;
case R.styleable.YearCostView_center_point_color:
centerPointColor = a.getColor(attr, Color.parseColor("#f05b48"));
break;
//中心圓環(huán)
case R.styleable.YearCostView_center_ring_width:
centerRingWidth = a.getLayoutDimension(attr, centerRingWidth);
break;
case R.styleable.YearCostView_center_ring_color:
centerRingColor = a.getColor(attr, ContextCompat.getColor(getContext(), android.R.color.white));
break;
//包裹中心圓環(huán)的圓環(huán)
case R.styleable.YearCostView_wraper_center_ring_width:
wraperCenterRingWidth = a.getLayoutDimension(attr, wraperCenterRingWidth);
break;
case R.styleable.YearCostView_wraper_center_ring_color:
wraperCenterRingColor = a.getColor(attr, Color.parseColor("#35383c"));
break;
//指針
case R.styleable.YearCostView_line_width:
lineWidth = a.getLayoutDimension(attr, lineWidth);
break;
case R.styleable.YearCostView_line_color:
lineColor = a.getColor(attr, Color.parseColor("#f05b48"));
break;
//inner ring
case R.styleable.YearCostView_inner_ring_width:
innerRingWidth = a.getLayoutDimension(attr, innerRingWidth);
break;
case R.styleable.YearCostView_inner_ring_color:
innerRingColor = a.getColor(attr, Color.parseColor("#25292c"));
break;
//target ring
case R.styleable.YearCostView_target_ring_width:
targetRingWidth = a.getLayoutDimension(attr, targetRingWidth);
break;
case R.styleable.YearCostView_target_ring_color:
targetRingColor = a.getColor(attr, Color.parseColor("#f05b48"));
break;
case R.styleable.YearCostView_target_bottom_ring_color:
targetBottomRingColor = a.getColor(attr, Color.parseColor("#303438"));
break;
//out ring
case R.styleable.YearCostView_out_ring_width:
outRingWidth = a.getLayoutDimension(attr, outRingWidth);
break;
case R.styleable.YearCostView_out_ring_color:
outRingColor = a.getColor(attr, Color.parseColor("#75777a"));
break;
//距離
case R.styleable.YearCostView_out_distance:
outDistance = a.getLayoutDimension(attr, outDistance);
break;
case R.styleable.YearCostView_inner_distance:
innerDistance = a.getLayoutDimension(attr, innerDistance);
break;
}
}
a.recycle();
自定義控件完整代碼
/**
* 類描述:年費(fèi)View
* 作者:xues
* 時(shí)間:2017年09月12日
*/
public class YearCostView extends View {
//中心圓環(huán)(白色圓環(huán))
private Paint centerRingPaint;
private int centerRingWidth = 2 * 6;
private int centerRingColor;
private RectF centerRingRectF;
//包裹中心圓環(huán)的圓環(huán)
private int wraperCenterRingColor;
private Paint wraperCenterRingPaint;
private int wraperCenterRingWidth = 4 * 6;
private RectF wraperCenterRingRectF;
//在目標(biāo)圓環(huán)里邊的圓環(huán)
private int innerRingColor;
private Paint innerRingPaint;
private int innerRingWidth = 1 * 6;
private RectF innerRingRectF;
//目標(biāo)圓環(huán)(紅色圓環(huán))
private int targetRingColor;
private Paint targetRingPaint;
private int targetRingWidth = 16 * 6;
private RectF targetRingRectF;
//目標(biāo)圓環(huán)壓著的圓環(huán)(紅色圓環(huán)壓著的圓環(huán))
private int targetBottomRingColor;
private Paint targetBottomRingPaint;
private int targetBottomRingWidth = 16 * 6;
private RectF targetBottomRingRectF;
//在目標(biāo)圓環(huán)外面的圓環(huán)
private int outRingColor;
private Paint outRingPaint;
private int outRingWidth = 1 * 6;
private RectF outRingRectF;
//指針
private int lineColor;
private Paint linePaint;
private int lineWidth = 2 * 6;
//中心紅點(diǎn)
private int centerPointColor;
private Paint centerPointPaint;
private int centerPointRadius = 1 * 6;
//圓環(huán)與圓環(huán)之間的距離
private int innerDistance = 120;
private int outDistance = 8;
private RotateAnimation mSweepAnim;//掃描動(dòng)畫
public YearCostView(Context context) {
this(context, null);
}
public YearCostView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public YearCostView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.YearCostView, defStyleAttr, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
//中心圓點(diǎn)
case R.styleable.YearCostView_center_point_radius:
centerPointRadius = a.getLayoutDimension(attr, centerPointRadius);
break;
case R.styleable.YearCostView_center_point_color:
centerPointColor = a.getColor(attr, Color.parseColor("#f05b48"));
break;
//中心圓環(huán)
case R.styleable.YearCostView_center_ring_width:
centerRingWidth = a.getLayoutDimension(attr, centerRingWidth);
break;
case R.styleable.YearCostView_center_ring_color:
centerRingColor = a.getColor(attr, ContextCompat.getColor(getContext(), android.R.color.white));
break;
//包裹中心圓環(huán)的圓環(huán)
case R.styleable.YearCostView_wraper_center_ring_width:
wraperCenterRingWidth = a.getLayoutDimension(attr, wraperCenterRingWidth);
break;
case R.styleable.YearCostView_wraper_center_ring_color:
wraperCenterRingColor = a.getColor(attr, Color.parseColor("#35383c"));
break;
//指針
case R.styleable.YearCostView_line_width:
lineWidth = a.getLayoutDimension(attr, lineWidth);
break;
case R.styleable.YearCostView_line_color:
lineColor = a.getColor(attr, Color.parseColor("#f05b48"));
break;
//inner ring
case R.styleable.YearCostView_inner_ring_width:
innerRingWidth = a.getLayoutDimension(attr, innerRingWidth);
break;
case R.styleable.YearCostView_inner_ring_color:
innerRingColor = a.getColor(attr, Color.parseColor("#25292c"));
break;
//target ring
case R.styleable.YearCostView_target_ring_width:
targetRingWidth = a.getLayoutDimension(attr, targetRingWidth);
break;
case R.styleable.YearCostView_target_ring_color:
targetRingColor = a.getColor(attr, Color.parseColor("#f05b48"));
break;
case R.styleable.YearCostView_target_bottom_ring_color:
targetBottomRingColor = a.getColor(attr, Color.parseColor("#303438"));
break;
//out ring
case R.styleable.YearCostView_out_ring_width:
outRingWidth = a.getLayoutDimension(attr, outRingWidth);
break;
case R.styleable.YearCostView_out_ring_color:
outRingColor = a.getColor(attr, Color.parseColor("#75777a"));
break;
//距離
case R.styleable.YearCostView_out_distance:
outDistance = a.getLayoutDimension(attr, outDistance);
break;
case R.styleable.YearCostView_inner_distance:
innerDistance = a.getLayoutDimension(attr, innerDistance);
break;
}
}
a.recycle();
initView();
}
/**
* 初始化參數(shù)
*/
private void initView() {
initPaint();
//初始化動(dòng)畫并設(shè)置動(dòng)畫持續(xù)時(shí)間為1000毫秒==1秒
mSweepAnim = new RotateAnimation();
mSweepAnim.setDuration(1000);
}
float centerX;//中心點(diǎn)x
//初始化矩形
private void initRectF() {
//中心圓環(huán)
float leftOrTop = centerX - centerRingWidth / 2F - centerPointRadius;
float rightOrBottom = centerX + centerRingWidth / 2F + centerPointRadius;
centerRingRectF = new RectF(leftOrTop, leftOrTop, rightOrBottom, rightOrBottom);
//包圍中心圓環(huán)的圓環(huán)
leftOrTop = centerX - centerRingWidth - centerPointRadius - wraperCenterRingWidth / 2F;
rightOrBottom = centerX + centerRingWidth + centerPointRadius + wraperCenterRingWidth / 2F;
wraperCenterRingRectF = new RectF(leftOrTop, leftOrTop, rightOrBottom, rightOrBottom);
//inner圓環(huán)
leftOrTop = centerX - centerPointRadius - centerRingWidth - wraperCenterRingWidth - innerDistance - innerRingWidth / 2F;
rightOrBottom = centerX + centerPointRadius + centerRingWidth + wraperCenterRingWidth + innerDistance + innerRingWidth / 2F;
innerRingRectF = new RectF(leftOrTop, leftOrTop, rightOrBottom, rightOrBottom);
//目標(biāo)圓環(huán)
leftOrTop = centerX - centerPointRadius - centerRingWidth - wraperCenterRingWidth - innerDistance - innerRingWidth - outDistance - targetRingWidth / 2F;
rightOrBottom = centerX + centerPointRadius + centerRingWidth + wraperCenterRingWidth + innerDistance + innerRingWidth + outDistance + targetRingWidth / 2F;
targetRingRectF = new RectF(leftOrTop, leftOrTop, rightOrBottom, rightOrBottom);
targetBottomRingRectF = new RectF(leftOrTop, leftOrTop, rightOrBottom, rightOrBottom);
//out圓環(huán)
leftOrTop = centerX - centerPointRadius - centerRingWidth - wraperCenterRingWidth - innerDistance - innerRingWidth - outDistance * 2 - targetRingWidth - outRingWidth / 2F;
rightOrBottom = centerX + centerPointRadius + centerRingWidth + wraperCenterRingWidth + innerDistance + innerRingWidth + outDistance * 2 + targetRingWidth + outRingWidth / 2F;
outRingRectF = new RectF(leftOrTop, leftOrTop, rightOrBottom, rightOrBottom);
}
/**
* 從里邊向外初始化畫筆
*/
private void initPaint() {
//中心點(diǎn)
centerPointPaint = new Paint();
centerPointPaint.setAntiAlias(true);
centerPointPaint.setStrokeWidth(2 * centerPointRadius);
centerPointPaint.setColor(centerPointColor);
centerPointPaint.setStyle(Paint.Style.FILL);
//中心圓環(huán)
centerRingPaint = new Paint();
centerRingPaint.setAntiAlias(true);
centerRingPaint.setStrokeWidth(centerRingWidth);
centerRingPaint.setColor(centerRingColor);
centerRingPaint.setStyle(Paint.Style.STROKE);
//包裹中心圓環(huán)的圓環(huán)
wraperCenterRingPaint = new Paint();
wraperCenterRingPaint.setAntiAlias(true);
wraperCenterRingPaint.setStrokeWidth(wraperCenterRingWidth);
wraperCenterRingPaint.setColor(wraperCenterRingColor);
wraperCenterRingPaint.setStyle(Paint.Style.STROKE);
//inner圓環(huán)
innerRingPaint = new Paint();
innerRingPaint.setAntiAlias(true);
innerRingPaint.setStrokeWidth(innerRingWidth);
innerRingPaint.setColor(innerRingColor);
innerRingPaint.setStyle(Paint.Style.STROKE);
//目標(biāo)圓環(huán)壓住的圓環(huán)
targetBottomRingPaint = new Paint();
targetBottomRingPaint.setAntiAlias(true);
targetBottomRingPaint.setStrokeWidth(targetRingWidth);
targetBottomRingPaint.setColor(targetBottomRingColor);
targetBottomRingPaint.setStyle(Paint.Style.STROKE);
//目標(biāo)圓環(huán)
targetRingPaint = new Paint();
targetRingPaint.setAntiAlias(true);
targetRingPaint.setStrokeWidth(targetRingWidth);
targetRingPaint.setColor(targetRingColor);
targetRingPaint.setStyle(Paint.Style.STROKE);
//外部圓環(huán)
outRingPaint = new Paint();
outRingPaint.setAntiAlias(true);
outRingPaint.setStrokeWidth(outRingWidth);
outRingPaint.setColor(outRingColor);
outRingPaint.setStyle(Paint.Style.STROKE);
//指針
linePaint = new Paint();
linePaint.setAntiAlias(true);
linePaint.setStrokeWidth(lineWidth);
linePaint.setColor(lineColor);
linePaint.setStyle(Paint.Style.FILL);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int wSize = 0;
//match_parent or set value
if (widthMode == MeasureSpec.EXACTLY) {
wSize = widthSize;
} else {
//wrap_content
if (widthMode == MeasureSpec.AT_MOST) {
wSize = 2 * (centerPointRadius + centerRingWidth + wraperCenterRingWidth + innerDistance + innerRingWidth + outDistance * 2 + targetRingWidth);
}
}
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int hSize = 0;
//match_parent or set value
if (heightMode == MeasureSpec.EXACTLY) {
hSize = heightSize;
} else {
//wrap_content
if (heightMode == MeasureSpec.AT_MOST) {
hSize = 2 * (centerPointRadius + centerRingWidth + wraperCenterRingWidth + innerDistance + innerRingWidth + outDistance * 2 + targetRingWidth);
;
}
}
centerX = widthSize / 2f;
initRectF();//初始化灰色圓環(huán)和多顏色圓環(huán)矩形
setMeasuredDimension(wSize, hSize);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//繪制中心點(diǎn)
canvas.save();
canvas.restore();
//繪制包裹中心圓環(huán)的圓環(huán)
canvas.save();
canvas.drawArc(wraperCenterRingRectF, 0, 360, false, wraperCenterRingPaint);
canvas.restore();
//繪制inner圓環(huán)
canvas.save();
canvas.drawArc(innerRingRectF, 0, 360, false, innerRingPaint);
canvas.restore();
//繪制指針
canvas.save();
canvas.translate(centerX, centerX);
canvas.rotate(mSweepAngle + 135);
canvas.drawLine(-2, -2, centerPointRadius + centerRingWidth + wraperCenterRingWidth + innerDistance + innerRingWidth, 0, linePaint);
canvas.restore();
//繪制中心圓環(huán)
canvas.save();
canvas.drawArc(centerRingRectF, 0, 360, false, centerRingPaint);
canvas.restore();
//繪制紅色圓點(diǎn)
canvas.save();
canvas.drawCircle(centerX, centerX, centerPointRadius, centerPointPaint);
canvas.restore();
//繪制目標(biāo)圓環(huán)壓住的圓環(huán)
canvas.save();
canvas.drawArc(targetBottomRingRectF, -225, 270, false, targetBottomRingPaint);
canvas.restore();
//繪制目標(biāo)圓環(huán)
canvas.save();
canvas.drawArc(targetRingRectF, -225, mSweepAngle, false, targetRingPaint);
canvas.restore();
//繪制out圓環(huán)
canvas.save();
canvas.drawArc(outRingRectF, -226, 272, false, outRingPaint);
canvas.restore();
}
float mSweepAngle;
/**
* 自定義旋轉(zhuǎn)動(dòng)畫
*/
public class RotateAnimation extends Animation {
/**
* Initializes expand collapse animation, has two types, collapse (1) and expand (0).
*/
public RotateAnimation() {
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
//interpolatedTime 范圍:0到1
mSweepAngle = BigDecimalUtil.mul(interpolatedTime, BigDecimalUtil.mul(BigDecimalUtil.div(curMoney, totalMoney), 270F));//當(dāng)前時(shí)間掃描的角度
postInvalidate();//重繪
}
}
float curMoney, totalMoney;
/**
* 設(shè)置價(jià)格
*
* @param curMoney 當(dāng)前價(jià)格
* @param totalMoney 總金額
*/
public void setMoney(float curMoney, float totalMoney) {
this.curMoney = curMoney;
this.totalMoney = totalMoney;
startAnimation(mSweepAnim);
}
}
使用篇
在布局中使用自定義控件
<包名.YearCostView
android:id="@+id/yearCostView"
android:layout_width="@dimen/px480dp"
android:layout_height="@dimen/px480dp"
android:layout_gravity="center"
android:background="#191d21"
app:center_point_color="#f05b48"
app:center_point_radius="@dimen/px6dp"
app:center_ring_color="#ffffff"
app:center_ring_width="@dimen/px6dp"
app:inner_distance="@dimen/px100dp"
app:inner_ring_color="#25292c"
app:inner_ring_width="@dimen/px2dp"
app:line_color="#f05b48"
app:line_width="@dimen/px6dp"
app:out_distance="@dimen/px10dp"
app:out_ring_color="#75777a"
app:out_ring_width="@dimen/px2dp"
app:target_bottom_ring_color="#303438"
app:target_ring_color="#f05b48"
app:target_ring_width="@dimen/px64dp"
app:wraper_center_ring_color="#35383c"
app:wraper_center_ring_width="@dimen/px12dp" />
在Activity中設(shè)置價(jià)格
yearCostView.setMoney(135,270);//左側(cè)為當(dāng)前金額近上,右側(cè)為總金額