CounDownView
1.第一步:设置attars ,目的可以在xml文件中可以配置:

<resources>
<declare-styleable name="CountDownView">
<attr name="background_color" format="color"/>
<attr name="conner_radius" format="dimension"/>
<attr name="text_size" format="dimension"/>
<attr name="text_color" format="dimension"/>
<attr name="count" format="integer"/>
</declare-styleable>
</resources>
2.第二步:定义默认数据:因为是倒计时控件,所以所需要的属性并不是太多:
- 半透明背景颜色
- 字体颜色
- 字体大小
- 圆角大小
- 默认控件宽度
- 默认控件高度
private static final int DEFAULT_BACKGROUND_COLOR = 0x66777777;
private static final float DEFAULT_CONNER_RADIUS = 5;//dp
private static final float DEFAULT_TEXT_SIZE = 14;//sp
private static final int DEFAULT_TEXT_COLOR = 0xffffffff;
private static final int DEFAULT_COUNT = 3;
private static final int DEFAULT_WIDTH = 180; //默认控件宽度
private static final int DEFAULT_HEIGHT = 90; //默认控件高度
3.通过getContext().obtainStyledAttributes获取xml属性值,并设置画笔的属性:
//获取属性
private void obtainStyleAttrs(AttributeSet attrs) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.CountDownView);
background_color = typedArray.getColor(R.styleable.CountDownView_background_color, DEFAULT_BACKGROUND_COLOR);
conner_radius = (int) typedArray.getDimension(R.styleable.CountDownView_conner_radius, dp2px(DEFAULT_CONNER_RADIUS));
texr_size = (int) typedArray.getDimension(R.styleable.CountDownView_text_size, sp2px(DEFAULT_TEXT_SIZE));
text_color = typedArray.getColor(R.styleable.CountDownView_text_color, DEFAULT_TEXT_COLOR);
count = typedArray.getInt(R.styleable.CountDownView_count, DEFAULT_COUNT);
bacPaint.setColor(background_color);
bacPaint.setStyle(Paint.Style.FILL);//充满
bacPaint.setAntiAlias(true);
textPaint.setTextSize(texr_size);
textPaint.setColor(text_color);
textPaint.setTextAlign(Paint.Align.CENTER);
typedArray.recycle();
}
4.onMeasue中获取宽高:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
drawWidth(widthMode,widthSize);
drawHeight(heightMode,heightSize);
setMeasuredDimension(mWidth,mHeight);
}
5.onDraw画椭圆和字:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
//画椭圆
RectF rect = new RectF(0, 0, mWidth, mHeight);
canvas.drawRoundRect(rect, conner_radius, conner_radius, bacPaint);
Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt();
int baseline = (int) ((rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2);
//画字
canvas.drawText(mText + "", rect.centerX(), baseline, textPaint);
canvas.restore();
}
下面是view的代码:
package com.sam.commonlib.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.MainThread;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.Scheduler;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import com.sam.commonlib.R;
import java.util.concurrent.TimeUnit;
public class CountDownView extends View {
private static final int DEFAULT_BACKGROUND_COLOR = 0x66777777;
private static final float DEFAULT_CONNER_RADIUS = 5;//dp
private static final float DEFAULT_TEXT_SIZE = 14;//sp
private static final int DEFAULT_TEXT_COLOR = 0xffffffff;
private static final int DEFAULT_COUNT = 3;
private static final int DEFAULT_WIDTH = 180; //默认控件宽度
private static final int DEFAULT_HEIGHT = 90; //默认控件高度
private int background_color;
private int conner_radius;
private int texr_size;
private int text_color;
private int count;
private Paint textPaint = new Paint();
private int mText;
private Paint bacPaint = new Paint();
private int mHeight, mWidth;
private Disposable disposable;
public CountDownView(Context context) {
this(context, null);
}
public CountDownView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CountDownView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
obtainStyleAttrs(attrs);
mText = count;
Observable.interval(500,1000, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Long>() {
@Override
public void onSubscribe(Disposable d) {
disposable = d;
}
@Override
public void onNext(Long aLong) {
mText --;
invalidate();
if (aLong ==count){
mText =0;
if (countOverListener !=null){
countOverListener.OnCountOverListener();
}
disposable.dispose();
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
//获取属性
private void obtainStyleAttrs(AttributeSet attrs) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.CountDownView);
background_color = typedArray.getColor(R.styleable.CountDownView_background_color, DEFAULT_BACKGROUND_COLOR);
conner_radius = (int) typedArray.getDimension(R.styleable.CountDownView_conner_radius, dp2px(DEFAULT_CONNER_RADIUS));
texr_size = (int) typedArray.getDimension(R.styleable.CountDownView_text_size, sp2px(DEFAULT_TEXT_SIZE));
text_color = typedArray.getColor(R.styleable.CountDownView_text_color, DEFAULT_TEXT_COLOR);
count = typedArray.getInt(R.styleable.CountDownView_count, DEFAULT_COUNT);
bacPaint.setColor(background_color);
bacPaint.setStyle(Paint.Style.FILL);//充满
bacPaint.setAntiAlias(true);
textPaint.setTextSize(texr_size);
textPaint.setColor(text_color);
textPaint.setTextAlign(Paint.Align.CENTER);
typedArray.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
drawWidth(widthMode,widthSize);
drawHeight(heightMode,heightSize);
setMeasuredDimension(mWidth,mHeight);
}
private void drawWidth(int widthMode, int widthSize) {
switch (widthMode){
case MeasureSpec.EXACTLY:
mWidth = widthSize;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
mWidth = DEFAULT_WIDTH;
break;
}
}
private void drawHeight(int heightMode, int heightSize) {
switch (heightMode){
case MeasureSpec.EXACTLY:
mHeight = heightSize;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
mHeight = DEFAULT_HEIGHT;
break;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
//画椭圆
RectF rect = new RectF(0, 0, mWidth, mHeight);
canvas.drawRoundRect(rect, conner_radius, conner_radius, bacPaint);
Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt();
int baseline = (int) ((rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2);
//画字
canvas.drawText(mText + "", rect.centerX(), baseline, textPaint);
canvas.restore();
}
private int dp2px(float dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
private int sp2px(float sp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
}
public interface CountOverListener {
void OnCountOverListener();
}
private CountOverListener countOverListener;
/**
* 供外部调用
*/
public void setOnCountOverListener(CountOverListener countOverListener){
this.countOverListener = countOverListener;
}
/**
* 供外部调用
*/
public void cancel(){
if (disposable!=null&&!disposable.isDisposed()){
disposable.dispose();
}
}
}