Android 自定义View 之 计时文字

简介: Android 自定义View 之 计时文字

前言


  在Android开发中,常常会有计时的一些操作,例如收验证码的时候倒计时,秒表的计时等等,于是我就有了一个写自定义View的想法,本文效果图。

e27b96f455c9450f8aa0be566acadd0b.gif


正文


  那么现在我们将想法换成现实,这个自定义View比较简单,我们来看怎么写的,首先我们还是在EasyView中进行添加。


一、XML样式


  根据上面的效果图,我们首先来确定XML中的属性样式,在attrs.xml中增加如下代码:

    <!--计时文字-->
    <declare-styleable name="TimingTextView">
        <!--倒计时-->
        <attr name="countdown" format="boolean" />
        <!--时间最大值-->
        <attr name="max" format="integer" />
        <!--时间单位,时:h,分:m,秒:s-->
        <attr name="unit">
            <enum name="h" value="1" />
            <enum name="m" value="2" />
            <enum name="s" value="3" />
        </attr>
    </declare-styleable>


  这里的计时文字目前有3个属性,第一个boolean用来确定是计时还是倒计时,第二个是最大时间,第三个是时间单位:时分秒。


二、构造方法


  之前我说自定义View有三种方式,一种是继承View,一种是继承现有的View,还有一种是继承ViewGroup,那么今天的这个计时文字,我们就可以继承现有的View,这样做的目的就是可以让我们减少一定的工作量,专注于功能上,下面我们在com.llw.easyview包下新建一个TimingTextView类,里面的代码如下所示:

public class TimingTextView extends MaterialTextView {
    /**
     * 时间单位
     */
    private int mUnit;
    /**
     * 计时最大值
     */
    private int mMax;
    /**
     * 是否倒计时
     */
    private boolean mCountDown;
    private int mTotal;
    /**
     * 是否计时中
     */
    private boolean mTiming;
    public TimingTextView(Context context) {
        this(context, null);
    }
    public TimingTextView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public TimingTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        @SuppressLint("CustomViewStyleable")
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TimingTextView);
        mCountDown = typedArray.getBoolean(R.styleable.TimingTextView_countdown, false);
        mMax = typedArray.getInteger(R.styleable.TimingTextView_max, 60);
        mUnit = typedArray.getInt(R.styleable.TimingTextView_unit, 3);
        typedArray.recycle();
    }
}


  因为有计时的缘故,所以我们需要一个计时监听,主要用于结束的时候进行调用,可以在com.llw.easyview下新建一个TimingListener接口,代码如下:

public interface TimingListener {
    void onEnd();
}


三、API方法


下面在TimingTextView中新增一些API方法和变量,首先增加变量:

    private TimingListener listener;
    private CountDownTimer countDownTimer;


然后增加API方法:

    /**
     * 设置时间单位
     *
     * @param unit 1,2,3
     */
    public void setUnit(int unit) {
        if (unit <= 0 || unit > 3) {
            throw new IllegalArgumentException("unit value can only be between 1 and 3");
        }
        mUnit = unit;
    }
    /**
     * 设置最大时间值
     *
     * @param max 最大值
     */
    public void setMax(int max) {
        mMax = max;
    }
    /**
     * 设置是否为倒计时
     *
     * @param isCountDown true or false
     */
    public void setCountDown(boolean isCountDown) {
        mCountDown = isCountDown;
    }
    public void setListener(TimingListener listener) {
        this.listener = listener;
    }
    public boolean isTiming() {
        return mTiming;
    }
    /**
     * 开始
     */
    public void start() {
        switch (mUnit) {
            case 1:
                mTotal = mMax * 60 * 60 * 1000;
                break;
            case 2:
                mTotal = mMax * 60 * 1000;
                break;
            case 3:
                mTotal = mMax * 1000;
                break;
        }
        if (countDownTimer == null) {
            countDownTimer = new CountDownTimer(mTotal, 1000) {
                @Override
                public void onTick(long millisUntilFinished) {
                    int time = 0;
                    if (mCountDown) {
                        time = (int)  (millisUntilFinished / 1000);
                        setText(String.valueOf(time));
                    } else {
                        time = (int) (mTotal / 1000 - millisUntilFinished / 1000);
                    }
                    setText(String.valueOf(time));
                }
                @Override
                public void onFinish() {
                    //倒计时结束
                    end();
                }
            };
            mTiming = true;
            countDownTimer.start();
        }
    }
    /**
     * 计时结束
     */
    public void end() {
        mTotal = 0;
        mTiming = false;
        countDownTimer.cancel();
        countDownTimer = null;
        if (listener != null) {
            listener.onEnd();
        }
    }


代码还是很简单的,你敢信,这个自定义View就写完了,不过可能存在一些问题,我将自定义View的代码都放到了一个library下面里,然后将这个library进行构建成aar,然后上传到mavenCentral()中。


四、使用


  然后我们修改一下activity_main.xml,代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">
    <com.easy.view.MacAddressEditText
        android:id="@+id/mac_et"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:boxBackgroundColor="@color/white"
        app:boxStrokeColor="@color/black"
        app:boxStrokeWidth="2dp"
        app:boxWidth="48dp"
        app:separator=":"
        app:textColor="@color/black"
        app:textSize="16sp" />
    <Button
        android:id="@+id/btn_mac"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="获取地址" />
    <com.easy.view.CircularProgressBar
        android:id="@+id/cpb_test"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        app:maxProgress="100"
        app:progress="10"
        app:progressbarBackgroundColor="@color/purple_500"
        app:progressbarColor="@color/purple_200"
        app:radius="80dp"
        app:strokeWidth="16dp"
        app:text="10%"
        app:textColor="@color/teal_200"
        app:textSize="28sp" />
    <Button
        android:id="@+id/btn_set_progress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="随机设置进度" />
    <com.easy.view.TimingTextView
        android:id="@+id/tv_timing"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="计时文字"
        android:textColor="@color/black"
        android:textSize="32sp"
        app:countdown="false"
        app:max="60"
        app:unit="s" />
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:gravity="center"
        android:orientation="vertical">
        <CheckBox
            android:id="@+id/cb_flag"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="计时" />
        <Button
            android:id="@+id/btn_start"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="开始" />
    </LinearLayout>
</LinearLayout>


预览效果如下图所示:

19febb87be4f4327bcaf1efa89f7a91e.png

下面我们回到MainActivity中,在onCreate()方法中添加如下代码:

        //计时文本操作
        TimingTextView tvTiming = findViewById(R.id.tv_timing);
        CheckBox cbFlag = findViewById(R.id.cb_flag);
        Button btnStart = findViewById(R.id.btn_start);
        tvTiming.setListener(new TimingListener() {
            @Override
            public void onEnd() {
                tvTiming.setText("计时文字");
                btnStart.setText("开始");
            }
        });
        cbFlag.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                cbFlag.setText(isChecked ? "倒计时" : "计时");
            }
        });
        //计时按钮点击
        btnStart.setOnClickListener(v -> {
            if (tvTiming.isTiming()) {
                //停止计时
                tvTiming.end();
                btnStart.setText("开始");
            } else {
                tvTiming.setMax(6);
                tvTiming.setCountDown(cbFlag.isChecked());
                tvTiming.setUnit(3);//单位 秒
                //开始计时
                tvTiming.start();
                btnStart.setText("停止");
            }
        });


下面运行一下看看:

e27b96f455c9450f8aa0be566acadd0b.gif


五、源码


如果对你有所帮助的话,不妨 Star 或 Fork,山高水长,后会有期~

源码地址:EasyView

相关文章
|
25天前
|
XML Java Android开发
Android实现自定义进度条(源码+解析)
Android实现自定义进度条(源码+解析)
53 1
|
3月前
|
Android开发 容器
Android UI设计: 什么是View和ViewGroup?
Android UI设计: 什么是View和ViewGroup?
36 0
|
5天前
|
移动开发 Java Unix
Android系统 自动加载自定义JAR文件
Android系统 自动加载自定义JAR文件
23 1
|
5天前
|
Shell Android开发 开发者
Android系统 自定义动态修改init.custom.rc
Android系统 自定义动态修改init.custom.rc
23 0
|
5天前
|
存储 安全 Android开发
Android系统 自定义系统和应用权限
Android系统 自定义系统和应用权限
19 0
|
29天前
|
Android开发
Android 开发 pickerview 自定义选择器
Android 开发 pickerview 自定义选择器
12 0
|
4月前
|
XML API Android开发
Android 自定义View 之 Dialog弹窗
Android 自定义View 之 Dialog弹窗
|
4月前
|
XML API Android开发
Android 自定义View 之 饼状进度条
Android 自定义View 之 饼状进度条
|
Android开发
Android Studio 自定义设置注释模板
Android Studio 自定义设置注释模板
372 0
Android Studio 自定义设置注释模板
|
6天前
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
24 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库