注册

Android 自定义View 之 计时文字

前言


  在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


作者:初学者_Study
来源:juejin.cn/post/7225045596029075511

0 个评论

要回复文章请先登录注册