Android 自定义View 之 计时文字

文章目录
  •   在Android开发中,常常会有计时的一些操作,例如收验证码的时候倒计时,秒表的计时等等,于是我就有了一个写自定义View的想法,本文效果图。
  •   那么现在我们将想法换成现实,这个自定义View比较简单,我们来看怎么写的,首先我们还是在EasyView中进行添加。
  •   根据上面的效果图,我们首先来确定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(); }
  • 下面在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
    • 前言
    • 正文
    • 一、XML样式
    • 二、构造方法
    • 三、API方法
    • 四、使用
    • 五、源码

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

    Android 自定义View 之 计时文字

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

      根据上面的效果图,我们首先来确定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();
    }

    下面在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>

    预览效果如下图所示:

    Android 自定义View 之 计时文字

    下面我们回到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("停止");
     }
     });

    下面运行一下看看:

    Android 自定义View 之 计时文字

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

    源码地址:EasyView

    © 版权声明

    相关文章