Android 自定义View实现计时文字详解

目录
  • 前言
  • 一、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

以上就是Android 自定义View实现计时文字详解的详细内容,更多关于Android 自定义View计时文字的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android源码解析onResume方法中获取不到View宽高

    目录 前言 问题1.为什么onCreate和onResume中获取不到view的宽高? 问题2.为什么View.post为什么可以获取View宽高? 结论 前言 有一个经典的问题,我们在Activity的onCreate中可以获取View的宽高吗?onResume中呢? 对于这类八股问题,只要看过都能很容易得出答案:不能. 紧跟着追问一个,那为什么View.post为什么可以获取View宽高? 今天来看看这些问题,到底为何? 今日份问题: 为什么onCreate和onResume中获取不到vie

  • Android ViewGroup事件分发和处理源码分析

    目录 正文 处理ACTION_DOWN事件 检测是否截断事件 不截断ACTION_DOWN事件 寻找处理事件的子View 事件分发给子View ViewGroup自己处理ACTION_DOWN事件 处理ACTION_DOWN总结 处理ACTION_MOVE事件 检测是否截断ACTION_MOVE事件 不截断ACTION_MOVE 事件分发给mFirstTouchTarget.child 截断ACTION_MOVE 处理 ACTION_UP 和 ACTION_CANCEL 事件 正确地使用requ

  • Android ViewModel创建不受横竖屏切换影响原理详解

    目录 ViewModel的创建方式 参数 1 ViewModelStoreOwner: 参数 2 Factory: ViewModel 为什么不受 Activity 横竖屏生命周期的影响 1.在 Activity 走到 onDestroy 方法时,做了判断 isChangingConfigurations 2.在 Activity 获取 getViewModelStore 时, 3.onRetainNonConfigurationInstance 调用 总结 1.介绍了ViewModel的创建

  • Android TextView冷门实用方法技巧

    目录 介绍 自定义字体 AutoLink 对齐模式 介绍 TextView 是 Android 开发中最常用的小部件之一.它用于在屏幕上显示文本.但是,TextView 有几个较少为人知的功能,对开发人员非常有用.在本博客文章中,我们将探讨其中的一些功能. 自定义字体 默认情况下,TextView 使用系统字体显示文本.但其实我们也可以导入我们自己的字体文件在 TextView 中使用自定义字体.这可以通过将字体文件添加到资源文件夹(res/font 或者 assets)并在 TextView

  • Android 自定义开源库 EasyView实现详解

    目录 配置EasyView 1. 工程build.gradle 或 settings.gradle配置 2. 使用模块的build.gradle配置 使用EasyView 一.MacAddressEditText 1. xml中使用 2. 属性介绍 3. 代码中使用 二.CircularProgressBar 1. xml中使用 2. 属性介绍 3. 代码中使用 三.TimingTextView 1. xml中使用 2. 属性介绍 3. 代码中使用 配置EasyView 这是一个简单方便的And

  • Android报错Didn‘t find class “android.view.x“问题解决原理剖析

    目录 前言 shrinkResources Safe Strict android.view.x 自定义保留 总结 前言 今天同事提到了一个问题,我们的一款App在debug包时没有问题,但是在release包时就是crash,报错如下: 可以看到问题是Didn‘t find class “android.view.x“,但是实际上我们代码中并没有这个类,由于是release包的问题,所以第一时间想到的是混淆问题,检查了一番后发现与混淆无关,经过上网查询发现有人提到说将build.gradle中

  • Android自定义View实现体重表盘详解流程

    目录 效果视频 分析 起始角度 圆弧 指针 代码 初始化属性 画布 绘制内圆弧 绘制外圆弧 绘制中间指针 绘制中间文字 绘制左右两边文字 动画 全部代码 下载链接 效果视频 分析 起始角度 如下图所示,起点角度为150,终点角度为240 圆弧 白色圆弧为整个圆弧范围,蓝色圆弧为根据数据变动而覆盖白色圆弧,蓝色圆弧比白色圆弧大一点,突出显示 InnerArcPaint.setStrokeWidth( Width * (float)0.1 ); OuterArcPaint.setStrokeWidt

  • Android自定义view实现侧滑栏详解

    目录 前言 需求 效果图 编写代码 主要问题 前言 上一篇文章学了下自定义View的onDraw函数及自定义属性,做出来的滚动选择控件还算不错,就是逻辑复杂了一些.这篇文章打算利用自定义view的知识,直接手撕一个安卓侧滑栏,涉及到自定义LayoutParams.带padding和margin的measure和layout.利用requestLayout实现动画效果等,有一定难度,但能重新学到很多知识! 需求 这里类似旧版QQ(我特别喜欢之前的侧滑栏),有两层页面,滑动不是最左侧才触发的,而是从

  • Android自定义View app更新动画详解

    为了做一个有温度的IT男,我决定在以后的文章中给大家分享一些看到的,听到的一些东西,如果你不喜欢请留言让我知道,如果你喜欢请点个赞.你也可留言写下自己想分享的东西,温暖你我他.这次分享的是一首歌,毛不易的<消愁>,分享这首歌主要是这首歌的歌词,借用薛之谦的评价:"我是研究歌词的人,我研究了十几年,但是你写到我想给你跪!",下面贴部分歌词供大家欣赏 一杯敬朝阳,一杯敬月光 唤醒我的向往,温柔了寒窗 于是可以不回头的逆风飞翔 不怕心头有雨,眼底有霜 一杯敬故乡,一杯敬远方 守着

  • Android 自定义返回按钮的实例详解

    Android 自定义返回按钮的实例详解 程序中我们有时候想让放回按钮按照自己的需求调整页面而不是单纯的按照系统返回上一级,这个问题很简单,重写 onKeyDown 方法即可. 下面方法,包含了 webview 中的返回上一页和普通 activity 的单击设置和双击退出程序. @Override public boolean onKeyDown(int keyCode, KeyEvent event) { //如果我们用的是webview页面,想返回网页的上一页设置这里就可以了 if (key

  • Android 使用View Binding的方法详解

    前言 Android Studio稳定版发布了3.6版本,带来了一些新变化:首先外观,启动页变了,logo改了,更显现代化:增加Multi Preview功能,能同时预览多个尺寸屏幕的显示效果:模拟器支持多屏:也终于支持全新的视图绑定组件View Binding:等. 之前我们与视图交互的方式有findViewById.kotlin中引入Android Kotlin Extensions后直接通过id进行访问.前者模板化严重,重复代码多:后者最为方便.现在有了新的选择–View Binding,

  • Android自定义View之边框文字、闪烁发光文字

    对现有控件进行扩展 1.绘制如下所示的两层背景的TextView 创建BorderTextView继承TextView 在构造函数中初始化一些基本数据 //外边框 mPaint1 = new Paint(); mPaint1.setColor(getResources().getColor(android.R.color.holo_blue_bright)); //画笔的样式,充满 mPaint1.setStyle(Paint.Style.FILL); //内边框 mPaint2 = new P

  • Android自定义日历控件实例详解

    为什么要自定义控件 有时,原生控件不能满足我们对于外观和功能的需求,这时候可以自定义控件来定制外观或功能:有时,原生控件可以通过复杂的编码实现想要的功能,这时候可以自定义控件来提高代码的可复用性. 如何自定义控件 下面我通过我在github上开源的Android-CalendarView项目为例,来介绍一下自定义控件的方法.该项目中自定义的控件类名是CalendarView.这个自定义控件覆盖了一些自定义控件时常需要重写的一些方法. 构造函数 为了支持本控件既能使用xml布局文件声明,也可在ja

  • Android自定义View实现简单文字描边功能

    本文实例为大家分享了Android实现简单文字描边功能的具体代码,供大家参考,具体内容如下 效果图: 实现代码: package com.example.zhangyu.myview.widget; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.

  • Android自定义view实现滚动选择控件详解

    目录 前言 需求 编写代码 主要问题 前言 上篇文章通过一个有header和footer的滚动控件(Viewgroup)学了下MeasureSpec.onMeasure以及onLayout,接下来就用一个滚动选择的控件(View)来学一下onDraw的使用,并且了解下在XML自定义控件参数. 需求 这里就是一个滚动选择文字的控件,还是挺常见的,之前用别人的,现在选择手撕一个,核心思想如下: 1.有三层不同大小及透明度的选项,选中项放在中间 2.接受一个列表的数据,静态时显示三个值,滚动时显示四个

  • Android自定义View中attrs.xml的实例详解

    Android自定义View中attrs.xml的实例详解 我们在自定义View的时候通常需要先完成attrs.xml文件 在values中定义一个attrs.xml 然后添加相关属性 这一篇先详细介绍一下attrs.xml的属性. <?xml version="1.0" encoding="utf-8"?> <resources> //自定义属性名,定义公共属性 <attr name="titleText" for

随机推荐