Android 自定義View實(shí)現(xiàn)計(jì)時(shí)文字詳解
前言
在Android開(kāi)發(fā)中,常常會(huì)有計(jì)時(shí)的一些操作,例如收驗(yàn)證碼的時(shí)候倒計(jì)時(shí),秒表的計(jì)時(shí)等等,于是我就有了一個(gè)寫(xiě)自定義View的想法,本文效果圖。

那么現(xiàn)在我們將想法換成現(xiàn)實(shí),這個(gè)自定義View比較簡(jiǎn)單,我們來(lái)看怎么寫(xiě)的,首先我們還是在EasyView中進(jìn)行添加。
一、XML樣式
根據(jù)上面的效果圖,我們首先來(lái)確定XML中的屬性樣式,在attrs.xml中增加如下代碼:
<!--計(jì)時(shí)文字-->
<declare-styleable name="TimingTextView">
<!--倒計(jì)時(shí)-->
<attr name="countdown" format="boolean" />
<!--時(shí)間最大值-->
<attr name="max" format="integer" />
<!--時(shí)間單位,時(shí):h,分:m,秒:s-->
<attr name="unit">
<enum name="h" value="1" />
<enum name="m" value="2" />
<enum name="s" value="3" />
</attr>
</declare-styleable>
這里的計(jì)時(shí)文字目前有3個(gè)屬性,第一個(gè)boolean用來(lái)確定是計(jì)時(shí)還是倒計(jì)時(shí),第二個(gè)是最大時(shí)間,第三個(gè)是時(shí)間單位:時(shí)分秒。
二、構(gòu)造方法
之前我說(shuō)自定義View有三種方式,一種是繼承View,一種是繼承現(xiàn)有的View,還有一種是繼承ViewGroup,那么今天的這個(gè)計(jì)時(shí)文字,我們就可以繼承現(xiàn)有的View,這樣做的目的就是可以讓我們減少一定的工作量,專(zhuān)注于功能上,下面我們?cè)?code>com.llw.easyview包下新建一個(gè)TimingTextView類(lèi),里面的代碼如下所示:
public class TimingTextView extends MaterialTextView {
/**
* 時(shí)間單位
*/
private int mUnit;
/**
* 計(jì)時(shí)最大值
*/
private int mMax;
/**
* 是否倒計(jì)時(shí)
*/
private boolean mCountDown;
private int mTotal;
/**
* 是否計(jì)時(shí)中
*/
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();
}
}
因?yàn)橛杏?jì)時(shí)的緣故,所以我們需要一個(gè)計(jì)時(shí)監(jiān)聽(tīng),主要用于結(jié)束的時(shí)候進(jìn)行調(diào)用,可以在com.llw.easyview下新建一個(gè)TimingListener接口,代碼如下:
public interface TimingListener {
void onEnd();
}
三、API方法
下面在TimingTextView中新增一些API方法和變量,首先增加變量:
private TimingListener listener;
private CountDownTimer countDownTimer;
然后增加API方法:
/**
* 設(shè)置時(shí)間單位
*
* @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;
}
/**
* 設(shè)置最大時(shí)間值
*
* @param max 最大值
*/
public void setMax(int max) {
mMax = max;
}
/**
* 設(shè)置是否為倒計(jì)時(shí)
*
* @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;
}
/**
* 開(kāi)始
*/
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() {
//倒計(jì)時(shí)結(jié)束
end();
}
};
mTiming = true;
countDownTimer.start();
}
}
/**
* 計(jì)時(shí)結(jié)束
*/
public void end() {
mTotal = 0;
mTiming = false;
countDownTimer.cancel();
countDownTimer = null;
if (listener != null) {
listener.onEnd();
}
}
代碼還是很簡(jiǎn)單的,你敢信,這個(gè)自定義View就寫(xiě)完了,不過(guò)可能存在一些問(wèn)題,我將自定義View的代碼都放到了一個(gè)library下面里,然后將這個(gè)library進(jìn)行構(gòu)建成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="隨機(jī)設(shè)置進(jìn)度" />
<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="計(jì)時(shí)文字"
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="計(jì)時(shí)" />
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="開(kāi)始" />
</LinearLayout>
</LinearLayout>
預(yù)覽效果如下圖所示:

下面我們回到MainActivity中,在onCreate()方法中添加如下代碼:
//計(jì)時(shí)文本操作
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("計(jì)時(shí)文字");
btnStart.setText("開(kāi)始");
}
});
cbFlag.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
cbFlag.setText(isChecked ? "倒計(jì)時(shí)" : "計(jì)時(shí)");
}
});
//計(jì)時(shí)按鈕點(diǎn)擊
btnStart.setOnClickListener(v -> {
if (tvTiming.isTiming()) {
//停止計(jì)時(shí)
tvTiming.end();
btnStart.setText("開(kāi)始");
} else {
tvTiming.setMax(6);
tvTiming.setCountDown(cbFlag.isChecked());
tvTiming.setUnit(3);//單位 秒
//開(kāi)始計(jì)時(shí)
tvTiming.start();
btnStart.setText("停止");
}
});
下面運(yùn)行一下看看:

五、源碼
如果對(duì)你有所幫助的話,不妨 Star 或 Fork,山高水長(zhǎng),后會(huì)有期~
源碼地址:EasyView
以上就是Android 自定義View實(shí)現(xiàn)計(jì)時(shí)文字詳解的詳細(xì)內(nèi)容,更多關(guān)于Android 自定義View計(jì)時(shí)文字的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Android?自定義開(kāi)源庫(kù)?EasyView實(shí)現(xiàn)詳解
- Android?TextView冷門(mén)實(shí)用方法技巧
- Android?TextView的maxEms和maxLength屬性區(qū)別
- Android報(bào)錯(cuò)Didn‘t?find?class?“android.view.x“問(wèn)題解決原理剖析
- Android?ViewModel創(chuàng)建不受橫豎屏切換影響原理詳解
- Android源碼解析onResume方法中獲取不到View寬高
- Android設(shè)置TextView樣式SpannableString教程
- Android ViewGroup事件分發(fā)和處理源碼分析
相關(guān)文章
Android重力傳感器實(shí)現(xiàn)滾動(dòng)的彈球
所謂傳感器能夠探測(cè)如光、熱、溫度、重力、方向 等等的功能,本文給大家介紹Android傳感器應(yīng)用之重力傳感器實(shí)現(xiàn)滾動(dòng)的彈球,對(duì)android重力傳感器相關(guān)知識(shí)感興趣的朋友一起看看吧2015-12-12
Android實(shí)現(xiàn)類(lèi)似3D Touch菜單功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)類(lèi)似3D Touch菜單功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03
Android訪問(wèn)assets本地json文件的方法
這篇文章主要介紹了Android訪問(wèn)assets本地json文件的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
android獲取當(dāng)前運(yùn)行Activity名字的方法
這篇文章主要介紹了android獲取當(dāng)前運(yùn)行Activity名字的方法,對(duì)比分析了兩種實(shí)現(xiàn)方法供大家選擇,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01
Android View移動(dòng)的3種方式總結(jié)
這篇文章主要給大家介紹了Android View移動(dòng)的三種方式,在介紹這三種方式之前先介紹了Android坐標(biāo)系的定義規(guī)則以及View的一些位置參數(shù)。有需要的朋友們可以參考借鑒。2016-09-09
Android嵌套滾動(dòng)NestedScroll的實(shí)現(xiàn)了解一下
嵌套滾動(dòng)已經(jīng)算一個(gè)比較常見(jiàn)的特效了,這篇文章主要介紹了Android嵌套滾動(dòng)NestedScroll的實(shí)現(xiàn)了解一下,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06

