一参滴、概述
本文詳細結合自定義 View 和 屬性動畫,講述如何自定義一個圓弧計步器漩仙。
二缆镣、實現步驟分析
- 確定自定義屬性芽突,編寫attrs.xml
- 在自定義View中獲取自定義屬性,做好初始化工作
- onMeasure(int widthMeasureSpec, int heightMeasureSpec) 確保正方形
- onDraw(Canvas canvas) 畫外圓弧、內圓弧董瞻、文字
- 提供調用方法
三寞蚌、具體實現
- 確定自定義屬性,編寫attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="StepView">
<attr name="outerColor" format="color" />
<attr name="innerColor" format="color" />
<attr name="borderWidth" format="dimension" />
<attr name="stepTextSize" format="dimension" />
<attr name="stepTextColor" format="color" />
</declare-styleable>
</resources>
- 在自定義View中獲取自定義屬性,做好初始化工作
public StepView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.StepView);
mOuterColor = array.getColor(R.styleable.StepView_outerColor,mOuterColor);
mInnerColor = array.getColor(R.styleable.StepView_innerColor, mInnerColor);
mBorderWidth = (int) array.getDimension(R.styleable.StepView_borderWidth,mBorderWidth);
mStepTextSize = array.getDimensionPixelSize(R.styleable.StepView_stepTextSize,mStepTextSize);
mStepTextColor = array.getColor(R.styleable.StepView_stepTextColor, mStepTextColor);
array.recycle();
mOutPaint = new Paint();
mOutPaint.setAntiAlias(true);
mOutPaint.setStrokeWidth(mBorderWidth);
mOutPaint.setColor(mOuterColor);
mOutPaint.setStrokeCap(Paint.Cap.ROUND);
mOutPaint.setStyle(Paint.Style.STROKE); // 畫筆空心
mInnerPaint = new Paint();
mInnerPaint.setAntiAlias(true);
mInnerPaint.setStrokeWidth(mBorderWidth);
mInnerPaint.setColor(mInnerColor);
mInnerPaint.setStrokeCap(Paint.Cap.ROUND);
mInnerPaint.setStyle(Paint.Style.STROKE); // 畫筆空心
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setColor(mStepTextColor);
mTextPaint.setTextSize(mStepTextSize);
// 寬高默認 30 dp
width = dp2px(context, 30);
height = dp2px(context, 30);
}
- onMeasure(int widthMeasureSpec, int heightMeasureSpec) 確保正方形
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 調用者在布局文件中可能 wrap_content
// 獲取模式 AT_MOST 默認30 dp
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode != MeasureSpec.AT_MOST){
width = MeasureSpec.getSize(widthMeasureSpec);
}
if (heightMode != MeasureSpec.AT_MOST){
height = MeasureSpec.getSize(heightMeasureSpec);
}
// 寬度高度不一致 取最小值力细,確保是個正方形
setMeasuredDimension(width > height ? height : width, width > height ? height : width);
}
- onDraw(Canvas canvas) 畫外圓弧睬澡、內圓弧、文字
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// int center = getWidth() / 2;
// int radius = getWidth() / 2 - mBorderWidth / 2;
// RectF rectF = new RectF(center - radius,center - radius ,center + radius,center + radius);
// 下面代碼由上面代碼簡化而成
RectF rectF = new RectF(mBorderWidth / 2 + getPaddingLeft(),mBorderWidth / 2 + getPaddingTop()
,getWidth() - (mBorderWidth / 2 + getPaddingRight()),getHeight() - (mBorderWidth / 2 + getPaddingBottom()));
canvas.drawArc(rectF,135,270,false,mOutPaint);
if(mStepMax == 0) return;
// 畫內圓弧 怎么畫肯定不能寫死 百分比 是使用者設置的從外面?zhèn)? float sweepAngle = (float)mCurrentStep / mStepMax;
canvas.drawArc(rectF, 135, sweepAngle * 270, false, mInnerPaint);
// 畫文字
String stepText = mCurrentStep+"";
Rect textBounds = new Rect();
mTextPaint.getTextBounds(stepText, 0, stepText.length(), textBounds);
int dx = getWidth() / 2 - textBounds.width() / 2;
// 基線 baseLine
Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt();
int dy = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
int baseLine = getHeight() / 2 + dy;
canvas.drawText(stepText,dx,baseLine,mTextPaint);
}
- 提供調用方法
/**
* 設置步數最大值
* @param stepMax
*/
public synchronized void setStepMax(int stepMax){
this.mStepMax = stepMax;
}
/**
* 設置當前步數
* @param currentStep
*/
public synchronized void setCurrentStep(int currentStep){
this.mCurrentStep = currentStep;
// 刷新
invalidate();
}
四眠蚂、結合屬性動畫使用
xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<com.vegen.StepView
android:id="@+id/step_view"
app:outerColor="@color/colorPrimary"
app:innerColor="@color/colorAccent"
app:borderWidth="20dp"
app:stepTextColor="@color/colorAccent"
app:stepTextSize="30sp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
Activity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final StepView qqStepView = (StepView) findViewById(R.id.step_view);
qqStepView.setStepMax(10000);
// 屬性動畫
ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, 8000);
valueAnimator.setDuration(1000);
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentStep = (float) animation.getAnimatedValue();
qqStepView.setCurrentStep((int)currentStep);
}
});
valueAnimator.start();
}
}
五煞聪、最終實現的效果
xiaoguotu.jpg