Android 自定义View 之 计时文字

news2024/11/15 20:06:12

计时文字

  • 前言
  • 正文
    • 一、XML样式
    • 二、构造方法
    • 三、API方法
    • 四、使用
    • 五、源码

前言

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

在这里插入图片描述

正文

  那么现在我们将想法换成现实,这个自定义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>

预览效果如下图所示:

在这里插入图片描述
下面我们回到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("停止");
            }
        });

下面运行一下看看:

在这里插入图片描述

五、源码

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

源码地址:EasyView

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/420317.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue2-黑马(八)

目录&#xff1a; &#xff08;1&#xff09;router-动态路由 &#xff08;2&#xff09;router-重置路由 &#xff08;3&#xff09;router-页面刷新 &#xff08;1&#xff09;router-动态路由 我们有这样一个需求&#xff0c;不同的用户根据自己的身份不一样&#xff0c;…

Seaborn 数据可视化基础

目录 介绍 知识点 Seaborn 介绍 快速优化图形 Seaborn 绘图 API 一、散点图&#xff1a; 参数hue hue hue_order 参数style 二 、线形图 三、类别图 绘制箱线图 绘制小提琴图 绘制增强箱线图 绘制点线图 绘制条形图 绘制计数条形图 四、分布图 五、回归图 …

nginx配置

单线程应用 稳定性高 系统资源消耗低 线程切换消耗小 对HTTP并发连接处理能力高 单台服务器可支持2w个并发请求 nginx与apache区别 Nginx相对于Apache的优点: 轻量级&#xff0c;同样是 web 服务&#xff0c;比Apache 占用更少的内存及资源&#xff0c;高并发&#xff0…

攻防世界-file_include(convert.iconv的使用)

代码审计&#xff0c;存在文件包含&#xff0c;直接上伪协议 发现不行&#xff0c;应该是存在字符过滤 知识盲区&#xff1a; 1.file://协议&#xff0c;需要填写绝对路径&#xff0c;只能读取txt文件&#xff0c;后面直接跟绝对路径。 file:///etc/passwd 2.php://filter …

深入浅出 Golang 内存管理

了解内存管理~ 前言&#xff1a; 本节课主要介绍了内存管理知识与自动内存管理机制&#xff0c;并对目前 Go 内存管理过程中存在的问题提出了解决方案&#xff0c;同时结合了上次课程学习的《Go 语言性能优化》相关知识&#xff0c;提供可行性的优化建议 … 自动内存管理 Go…

spring-boot怎么扫描不在启动类所在包路径下的bean

前言&#xff1a; 项目中有多个模块&#xff0c;其中有些模块的包路径不在启动类的子路径下&#xff0c;此时我们怎么处理才能加载到这些类&#xff1b; 1 使用SpringBootApplication 中的scanBasePackages 属性; SpringBootApplication(scanBasePackages {"com.xxx.xx…

C++linux高并发服务器项目实践 day5

Clinux高并发服务器项目实践 day5程序和进程单道、多道程序设计时间片并行和并发进程控制块&#xff08;PCB&#xff09;进程状态转换进程的状态进程相关命令进程号和相关函数进程创建父子进程的关系GDB多进程调试程序和进程 程序是包含一系列信息的文件&#xff0c;这些信息描…

你知道怎么实现定时任务吗?

诸位读者都知道笔者写东西都是用到才写&#xff0c;笔者的学习足迹自从参加工作之后就是 非系统 学习了&#xff0c;公司里源代码只要有笔者不知道的技术细节&#xff0c;笔者就会仔细的研究清楚&#xff0c;笔者是不喜欢给自己留下问题的那种学习习惯。 为何要写 笔者最近负…

如何使用Thymeleaf给web项目中的网页渲染显示动态数据?

编译软件&#xff1a;IntelliJ IDEA 2019.2.4 x64 操作系统&#xff1a;win10 x64 位 家庭版 服务器软件&#xff1a;apache-tomcat-8.5.27 目录一. 什么是Thymeleaf&#xff1f;二. MVC2.1 为什么需要MVC&#xff1f;2.2 MVC是什么&#xff1f;2.3 MVC和三层架构之间的关系及工…

AI绘图体验:想象力无限,创作无穷!(文生图)

基础模型&#xff1a;3D二次元 PIXEL ART &#xff08;1&#xff09;16-bit pixel art, outside of caf on rainy day, light coming from windows, cinematic still(电影剧照), hdr (2) 16-bit pixel art, island in the clouds, by studio ghibli&#xff08;吉卜力工作室…

配置基于WSL2的Docker环境并支持CUDA

导言 Content 正如前文windows 10 开启WSL2介绍的&#xff0c;我们可以在windows10中使用linux子系统。今天本文介绍如何在此基础上安装Docker并支持在wsl中使用GPU。 准备工作 加入windows insider preview。建议选Dev通道&#xff0c;不要选Beta。 安装Nvidia WSL2-compa…

【数据结构】-计数排序

&#x1f387;作者&#xff1a;小树苗渴望变成参天大树 &#x1f389; 作者宣言&#xff1a;认真写好每一篇博客 &#x1f38a;作者gitee:link 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作 者 点 点 关 注 吧&#xff01; 文章目录前言一、计数排序二、排序算法复杂度…

Nginx网站服务配置

一、Nginx概述 1.1 Nginx概述 Nginx&#xff1a; Nginx 是开源、高性能、高可靠的 Web 和反向代理服务器&#xff0c;而且支持热部署&#xff0c;几乎可以做到 7 * 24 小时不间断运行&#xff0c;即使运行几个月也不需要重新启动&#xff0c;还能在不间断服务的情况下对软件…

分布式计算技术(上):经典计算框架MapReduce、Spark 解析

当一个计算任务过于复杂不能被一台服务器独立完成的时候&#xff0c;我们就需要分布式计算。分布式计算技术将一个大型任务切分为多个更小的任务&#xff0c;用多台计算机通过网络组装起来后&#xff0c;将每个小任务交给一些服务器来独立完成&#xff0c;最终完成这个复杂的计…

07 -全局状态管理

全局状态管理 7-1&#xff1a;开篇 在上一章中我们完成了 “一半” 的文章搜索功能&#xff0c;并且留下了一些问题。那么这些历史残留的问题&#xff0c;我们将会在本章节中通过 全局状态管理工具 进行处理。 那么究竟什么是 全局状态管理工具&#xff0c;如何在 uniapp 中…

【Flutter进阶】聊一聊组件中的生命周期、状态管理及局部重绘

前言 说到生命周期&#xff0c;熟悉Android开发的小伙伴一定第一时间会想到Activity的生命周期&#xff0c;由于在Flutter中一切都是组件&#xff0c;所以组件的生命周期其实是类似的。 在这个过程中组件的状态——State就非常重要&#xff0c;它记录这整个组件内可变部分的状…

【SSM整合】1—Spring和Mybatis整合

⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记链接&#x1f449;https://github.com/A-BigTree/Code_Learning ⭐⭐⭐⭐⭐⭐ Spring专栏&#x1f449;https://blog.csdn.net/weixin_53580595/category_12279588.html SpringMVC专栏&#x1f449;htt…

linux安装kafka

目录 目录 一.安装包准备&#xff1a; 二.解压安装&#xff1a; 先将该安装包放入到/opt/install目录&#xff1a; 解压该文件到soft目录中&#xff1a; 改名&#xff0c;方便后续使用&#xff1a; 三修改其中配置和配置环境变量&#xff1a; 3.1 修改/opt/soft/kafka2…

camunda工作流引擎开发架构

Camunda的开发架构可以分为前端开发架构和后端开发架构。 前端开发架构&#xff1a; Camunda前端使用Angular框架进行开发&#xff0c;主要包括以下组件&#xff1a; 1、Cockpit&#xff1a;流程监控和管理界面。 2、Tasklist&#xff1a;任务管理和审批界面。 3、Admin&…

答题积分小程序云开发实战-开篇:项目介绍以及效果图

答题积分小程序云开发实战 开篇:项目介绍以及效果图 前言 我也看过不少的册子或者文章,大部分都很优秀,但也有的就长篇累牍,从时代背景讲起,复述各种基本概念、底层原理......嗯,看似很高级~ 但我阅读的时候,给我的感觉是,把你绕晕、把你劝退的感觉,相信大家都有同感,…