安卓自定义计时器控件

目录

 

前言

一、项目效果展示

二、自定义TextView

2.1 自定义属性

2.2 配置属性

三、实现计时器

3.1 技术选型

3.2 代码实现

四、具体使用

4.1 布局引用

4.2 API调用

附:控件源代码


前言

因为最近项目里面需要记录通话时长,那么就要用到计时器,想着去网上搜一个现成的直接拿过来用呢,结果百度搜到的都是自定义倒计时控件,偶尔有几个是正向计时的,但是看了他们的实现都不太符合我的要求,所以最后只能自己动手写一个了。基本思路就是封装一个自定义的TextView,把计时的功能做到里面去,在需要计时的地方直接在XML里面全类名引用一下这个控件,然后代码里调用几个API就能搞定。既然思路已经确定,那就照着做吧。

一、项目效果展示

没有效果图总感觉自己是在耍流氓,所以还是录了一个,让大家能够更直观的感受一下这个控件是个什么玩意,如下图所示:

二、自定义TextView

关于自定义View相关的知识,这里并不会多讲,一是我们的重点不在这里,二是我本身掌握的也不好,自定义View这块是通往安卓高级工程师的必备技能,所以我还在努力。因此这里也会使用最简单的自定义View来封装这个控件,这里选用的是继承自系统控件TextView,所以这里不用重写onMeasure()方法去测量宽高,系统已经为我们测量好了,这样就极大的减轻了我们的工作量,那么接下来就正式来处理这个自定义View吧(简单级别的)。

2.1 自定义属性

关于自定义属性这个需要根据你自己的业务去考虑需要哪些属性,我这里就简单的写了两个,具体步骤如下:

在values文件夹下面新建一个attrs.xml文件,然后就可以定义我们需要的属性了,我这里只定义了文字大小和颜色:

<declare-styleable name="DigitalTimer">
    <attr name="textColor" format="color" />
    <attr name="textSize" format="dimension" />
</declare-styleable>

2.2 配置属性

定义一个类DigitalTimer继承自TextView,重写单参(代码中new的时候使用)和双参(布局中引入使用)的构造方法,然后开始配置需要的相关属性,代码如下:

private static final float DEFAULT_TEXT_SIZE = 12;
private static final int DEFAULT_TEXT_COLOR = Color.WHITE;
private float textSize;
private int textColor;

public DigitalTimer(Context context) {
    super(context);
    init();
}

public DigitalTimer(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DigitalTimer);
    textSize = a.getDimension(R.styleable.DigitalTimer_textSize, DEFAULT_TEXT_SIZE);
    textColor = a.getColor(R.styleable.DigitalTimer_textColor, DEFAULT_TEXT_COLOR);
    a.recycle();
    init();
}

//初始化
private void init() {
    setTextSize(textSize);
    setTextColor(textColor);
    setGravity(Gravity.CENTER);
    setBackgroundColor(Color.TRANSPARENT);
}

三、实现计时器

3.1 技术选型

这里选用的是rxjava中的interval操作符去实现的,链式调用看着就很舒服,先来了解一下interval操作符:

3.2 代码实现

这里调用interval操作符,构造方法里面分别传入了1,1,TimeUnit.SECONDS,分别表示延时1秒之后,每隔1秒发送一次数据,我们定义一个变量mCurrentSecond,用来记录当前的秒数,初始值为0,之后每次递增1,然后按照时分秒的转换关系进行相应的转换处理,最后把值设置到TextView上面去,具体代码如下:

    //开始计时
    public void start() {
        mDisposable = Observable.interval(1, 1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        mCurrentSecond++;
                        int hour = mCurrentSecond / 3600;
                        int minute = (mCurrentSecond % 3600) / 60;
                        int second = mCurrentSecond % 60;

                        if (second < 10) { //处理秒
                            seconds = "0" + second;
                        } else {
                            seconds = String.valueOf(second);
                        }

                        if (minute < 10) { //处理分
                            minutes = "0" + minute;
                        } else {
                            minutes = String.valueOf(minute);
                        }

                        if (hour < 10) { //处理小时
                            hours = "0" + hour;
                        } else {
                            hours = String.valueOf(hour);
                        }

                        //设置数据
                        setText(String.format("%s:%s:%s", hours, minutes, seconds));
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        LogUtil.e("自定义计时器数据异常------" + throwable.getMessage());
                    }
                });

    }

相应的还封装了停止计时和数据清零的方法,如下所示:

    //停止计时
    public void stop() {
        LogUtil.e("当前计时时长----->" + getText().toString());
        if (mDisposable != null) {
            mDisposable.dispose();
        }
    }

    //重置数据
    @SuppressLint("SetTextI18n")
    public void reset() {
        mCurrentSecond = 0;
        setText("00:00:00");
        stop();
    }

四、具体使用

4.1 布局引用

首先在布局文件中引用这个控件:

<com.nari.yihui.widget.DigitalTimer
        android:id="@+id/timer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:textSize="@dimen/font_size_18"
        app:textColor="@color/colorAccent"
        android:text="00:00:00"/>

4.2 API调用

然后在对应的界面中调用开始计时、停止计时的方法就OK了:

    @OnClick({R.id.button1, R.id.button2, R.id.button3})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.button1:
                timer.start();
                break;
            case R.id.button2:
                timer.stop();
                break;
            case R.id.button3:
                timer.reset();
                break;
        }
    }

这样就完成了这个控件的封装,是不是还挺简单的,如果发现了什么问题,欢迎给我留言。

附:控件源代码

package com.nari.yihui.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.TextView;

import com.nari.yihui.R;
import com.nari.yihui.utils.LogUtil;

import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;

/**
 * 包名:com.nari.yihui.widget
 * 文件名:   DigitalTimer
 * 创建时间:   2018/7/25 11:29
 * 作者:     纪安奇
 * 作用:自定义计时器控件
 */

@SuppressWarnings({"RedundantThrows"})
@SuppressLint("AppCompatCustomView")
public class DigitalTimer extends TextView {
    private static final float DEFAULT_TEXT_SIZE = 12;
    private static final int DEFAULT_TEXT_COLOR = Color.WHITE;
    private float textSize;
    private int textColor;
    private int mCurrentSecond = 0; //当前秒
    private String hours, minutes, seconds; //展示的时分秒
    private Disposable mDisposable;

    public DigitalTimer(Context context) {
        super(context);
        init();
    }

    public DigitalTimer(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DigitalTimer);
        textSize = a.getDimension(R.styleable.DigitalTimer_textSize, DEFAULT_TEXT_SIZE);
        textColor = a.getColor(R.styleable.DigitalTimer_textColor, DEFAULT_TEXT_COLOR);
        a.recycle();
        init();
    }

    //初始化
    private void init() {
        setTextSize(textSize);
        setTextColor(textColor);
        setGravity(Gravity.CENTER);
        setBackgroundColor(Color.TRANSPARENT);
    }

    //开始计时
    public void start() {
        mDisposable = Observable.interval(1, 1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        mCurrentSecond++;
                        int hour = mCurrentSecond / 3600;
                        int minute = (mCurrentSecond % 3600) / 60;
                        int second = mCurrentSecond % 60;

                        if (second < 10) { //处理秒
                            seconds = "0" + second;
                        } else {
                            seconds = String.valueOf(second);
                        }

                        if (minute < 10) { //处理分
                            minutes = "0" + minute;
                        } else {
                            minutes = String.valueOf(minute);
                        }

                        if (hour < 10) { //处理小时
                            hours = "0" + hour;
                        } else {
                            hours = String.valueOf(hour);
                        }

                        //设置数据
                        setText(String.format("%s:%s:%s", hours, minutes, seconds));
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        LogUtil.e("自定义计时器数据异常------" + throwable.getMessage());
                    }
                });

    }

    //停止计时
    public void stop() {
        LogUtil.e("当前计时时长----->" + getText().toString());
        if (mDisposable != null) {
            mDisposable.dispose();
        }
    }

    //重置数据
    @SuppressLint("SetTextI18n")
    public void reset() {
        mCurrentSecond = 0;
        setText("00:00:00");
        stop();
    }

}

猜你喜欢

转载自blog.csdn.net/JArchie520/article/details/81220923