CountdownView的简单使用

来源:互联网 发布:孩子气的战争动作数据 编辑:程序博客网 时间:2024/05/16 12:42

下面上效果图:

CountdownView是一个Android 倒计时控件,使用Canvas绘制,支持多种样式,Android Studio导入:

compile 'com.github.iwgang:countdownview:1.2'

代码调用实例:

CountdownView mCvCountdownView = (CountdownView)findViewById(R.id.cv_countdownViewTest1);mCvCountdownView.start(995550000);/**或者自己编写倒计时逻辑,然后调用updateShow来更新UI*/for (int time=0; time<1000; time++) {    mCvCountdownView.updateShow(time);}

xxx.xml引用实例:

<cn.iwgang.countdownview.CountdownView    android:layout_width="wrap_content"    android:layout_height="wrap_content"    app:isHideTimeBackground="true"    app:isShowDay="true"    app:isShowHour="true"    app:isShowMinute="true"    app:isShowSecond="true"    app:isShowMillisecond="true"    app:timeTextColor="#000000"    app:timeTextSize="22sp"    app:isTimeTextBold="true"    app:suffixGravity="bottom"    app:suffixTextColor="#000000"    app:suffixTextSize="12sp"    app:suffixHour="时"    app:suffixMinute="分"    app:suffixSecond="秒"    app:suffixMillisecond="毫秒" />

下面是相关自定义的属性表(属性名称、类型、默认值)

isHideTimeBackground    boolean true 隐藏倒计时背景timeBgColor color   #444444 倒计时的背景色timeBgSize  dimension   timeSize + 2dp * 4 倒计时背景大小timeBgRadius    dimension   0 倒计时背景的圆角isShowTimeBgDivisionLine    boolean true 倒计时的横向的分割线timeBgDivisionLineColor color   #30FFFFFF 倒计时的横向的分割线颜色timeBgDivisionLineSize  dimension   0.5dp 倒计时的横向的分割线高度timeTextSize    dimension   12sp 倒计时的文字大小timeTextColor   color   #000000 倒计时的文字颜色isTimeTextBold  boolean false 倒计时文字所在的边框isShowDay   boolean 自动显示 (天 > 1 显示, = 0 隐藏)isShowHour  boolean 自动显示 (小时 > 1 显示, = 0 隐藏)isShowMinute    boolean true 是否显示分钟isShowSecond    boolean true 是否显示秒isShowMillisecond   boolean false 是否显示毫秒suffixTextSize  dimension   12sp 添加的分号:的大小suffixTextColor color   #000000 添加的分号:的颜色isSuffixTextBold    boolean false 添加的分号:的边框suffixGravity   'top' or 'center' or 'bottom'   'center' 添加的分号:对齐方式suffix  string  ':' 添加的分号:默认值suffixDay   string  null 天默认值suffixHour  string  null 时默认值suffixMinute    string  null 分默认值suffixSecond    string  null 秒默认值suffixMillisecond   string  null 毫秒默认值suffixLRMargin  dimension   left 3dp right 3dp 间距默认左右各3dpsuffixDayLeftMargin dimension   0suffixDayRightMargin    dimension   0suffixHourLeftMargin    dimension   0suffixHourRightMargin   dimension   0suffixMinuteLeftMargin  dimension   0suffixMinuteRightMargin dimension   0suffixSecondLeftMargin  dimension   0suffixSecondRightMargin dimension   0suffixMillisecondLeftMargin dimension   0当我们使用ListView 或者RecycleView等控件使用倒计时,会出现这个情况一个界面有多个倒计时,那么他的回调函数在Activity、Fragment里面只有一个,这是后我们可以选择添加Tag标签,回调函数onEnd里判断Tag值匹配执行响应函数,个人觉得在Adapter里面使用有个更好的方法,onEnd(CountdownView ,position)把position回调回来就简单多了,

先看给控件添加Tag回调实例:

    // 第1步,设置tag    mCvCountdownView.setTag(R.id.name, uid);    // 第2步,从回调中的CountdownView取回tag    @Override    public void onEnd(CountdownView cv) {        Object nameTag = cv.getTag(R.id.uid);        if (null != nameTag) {            Log.i(TAG, "name = " + nameTag.toString());        }    }

动态显示/隐藏某些时间 (如:开始显示时、分、秒,后面到指定时间改成分、秒、毫秒)

customTimeShow(boolean isShowDay,                boolean isShowHour,               boolean  isShowMinute,               boolean isShowSecond,               boolean isShowMillisecond)

指定间隔时间回调和倒计时结束回调:

setOnCountdownIntervalListener(long interval, OnCountdownIntervalListener onCountdownIntervalListener);setOnCountdownEndListener(OnCountdownEndListener onCountdownEndListener);

倒计时的抽象类CustomCountDownTimer ,调用其start、stop(同步方法)方法控制倒计时,Handler控制进度,重点在这里:

 while (delay < 0) delay += mCountdownInterval; sendMessageDelayed(obtainMessage(MSG), delay);

倒计时没结束继续发消息while循环直到结束,下面再来看正主CountdownView:

public class CountdownView extends View {    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);        this.mContext = context;        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CountdownView);        mTimeBgColor = ta.getColor(R.styleable.CountdownView_timeBgColor, 0xFF444444);        mTimeBgRadius = ta.getDimension(R.styleable.CountdownView_timeBgRadius, 0);       //..........................属性解析略...........................        }}

构造方法调用initPaint初始化画笔操作,两个个人平时不常用属性:setFakeBoldText(true);//true设定,false清除,这里是设置中文仿“粗体”-.setTextAlign(Paint.Align.CENTER);设置文字对齐方式,系统提供了几种,当这些不满足我们需求比如盖章那种类型的就需要Path配合绘制完成,这里不多说

   private void initPaint() {        // time text        mTimeTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mTimeTextPaint.setColor(mTimeTextColor);        mTimeTextPaint.setTextAlign(Paint.Align.CENTER);        mTimeTextPaint.setTextSize(mTimeTextSize);        if (isTimeTextBold) {            mTimeTextPaint.setFakeBoldText(true);        }        //..........................更多Paint初始化略...........................   

initSuffix(true);根据:天时分秒毫秒等是否显示初始化值,initSuffixMargin()初始化边距值,用到了dp转px,sp转px,真心佩服写着控件的主人,耐心真好!!初始化还在继续,测量文字以便于onDraw绘制(有人说这种测量方法有误差,配合mPaint.measureText()就完美了)

  Rect rect = new Rect();        mTimeTextPaint.getTextBounds("00", 0, 2, rect);        mTimeTextWidth = rect.width();        mTimeTextHeight = rect.height();        mTimeTextBottom = rect.bottom;

构造函数说完该轮到onMeasure测量函数了

  @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //根据现实的元素计算总宽度        mContentAllWidth = getAllContentWidth();        //根据现实的元素计算总高度        mContentAllHeight = isHideTimeBackground ? (int) mTimeTextHeight : (int) mTimeBgSize;        //更具传入类型和MeasureSpec获取响应的mode size,计算宽高        mViewWidth = measureSize(1, mContentAllWidth, widthMeasureSpec);        mViewHeight = measureSize(2, mContentAllHeight, heightMeasureSpec);        //测量到控件的宽高后重新设置(setMeasuredDimension方法觉得view视图大小)         setMeasuredDimension(mViewWidth, mViewHeight);        //又开始一些列初始化了,计算这些值好累O(∩_∩)O~        initTimeTextBaselineAndTimeBgTopPadding();        initLeftPaddingSize();        initTimeBgRect();    }

measure测量个人感觉下面这种方式比较喜欢,以前我都全部一股脑的写在了onMeasure里面

private int measureSize(int specType, int contentSize, int measureSpec) {        int result;        //获取测量的模式和Size        int specMode = MeasureSpec.getMode(measureSpec);        int specSize = MeasureSpec.getSize(measureSpec);        if (specMode == MeasureSpec.EXACTLY) {            result = Math.max(contentSize, specSize);        } else {            result = contentSize;            if (specType == 1) {                // 根据传人方式计算宽                result += (getPaddingLeft() + getPaddingRight());            } else {                // 根据传人方式计算高                result += (getPaddingTop() + getPaddingBottom());            }        }        return result;    }

太多的初始化操作了,太多的属性了,我终于发现我和大神的区别了,我的耐心和他们没法比,哎..再来看你onDraw绘制:

  @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        float mHourLeft;        float mMinuteLeft;        float mSecondLeft;        if (isHideTimeBackground) {            // no background           //*****drawText 时分秒等略***                canvas.drawText(formatNum(mDay), mLeftPaddingSize + mDayTimeTextWidth / 2, mTimeTextBaseline, mTimeTextPaint);            //****根据是否显示时分秒等控制是否绘制*******            if (isShowSecond) {                // draw second text                canvas.drawText(formatNum(mSecond), mSecondLeft + mTimeTextWidth / 2, mTimeTextBaseline, mTimeTextPaint);    } else {            // 要绘制背景            if (isShowDay) {                // 绘制带圆角的                canvas.drawRoundRect(mDayBgRectF, mTimeBgRadius, mTimeBgRadius, mTimeTextBgPaint);                绘制横向的分割线                if (isShowTimeBgDivisionLine) {                    // draw day background division line                    canvas.drawLine(mLeftPaddingSize, mTimeBgDivisionLineYPos, mLeftPaddingSize + mDayTimeBgWidth, mTimeBgDivisionLineYPos, mTimeTextBgDivisionLinePaint);                }               //********************代码绘制太多都略过吧*********************    }

在我们调用countdownView.start方法本质是调用了辅助类的start方法:

/**     * start countdown     * @param millisecond millisecond     */    public void start(long millisecond) {        if (millisecond <= 0) {            return ;        }        if (null != mCustomCountDownTimer) {            mCustomCountDownTimer.stop();            mCustomCountDownTimer = null;        }        long countDownInterval;        if (isShowMillisecond) {            countDownInterval = 10;            updateShow(millisecond);        } else {            countDownInterval = 1000;        }        mCustomCountDownTimer = new CustomCountDownTimer(millisecond, countDownInterval) {            @Override            public void onTick(long millisUntilFinished) {                updateShow(millisUntilFinished);            }            @Override            public void onFinish() {                // countdown end                allShowZero();                // 倒计时结束了回调该函数                if (null != mOnCountdownEndListener) {                    mOnCountdownEndListener.onEnd(CountdownView.this);                }            }        };        mCustomCountDownTimer.start();    }