前言:
前陣子收到一個問題。其實收到問題的當下就想到怎麼做了,順便實作一下吧!
其實這三個東西感覺自己都會,整合起來就會卡卡的,可能就像英文一樣吧XD
本篇就以CountDownTimer為主。
情境大致上是這樣 —
使用者按下Button然後跳出TimePicker,選好時間按確定之後,開始倒數。
在倒數的同時,ProgressBar會跟著百分比做改動。
重點程式碼:
會用到之前寫過的東西ProgrssBar —
http://nikeru8.blogspot.tw/2017/09/android-progressbar.html
時間選擇器 —
http://nikeru8.blogspot.tw/2016/12/androidtimepickerdialog.html
CountDownTimer 這是官方文檔 —
https://developer.android.com/reference/android/os/CountDownTimer.html
CountDownTimer使用方法
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
上面這段直接copy官方文檔內的範例
可以看到CountDownTimer( 你要計時的毫秒 , 多少毫秒運行一次 )
上圖可以直接講完這method的所有使用方式。
完整程式碼:
![]() | |
| activity_main.xml |
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context="com.hello.kaiser.progressbardemo.MainActivity">
<LinearLayout
android:id="@+id/bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ProgressBar
android:id="@+id/progress_bar"
style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:layout_weight="9" />
<TextView
android:id="@+id/progress_tv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:text="0%" />
</LinearLayout>
<View
android:id="@+id/line"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="@+id/bar_layout"
android:layout_marginTop="20dp"
android:background="#ffaa" />
<TextView
android:id="@+id/show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/line"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:text="time" />
<Button
android:id="@+id/show_picker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/show"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:onClick="timePickerBtn"
android:text="picker" />
<Button
android:onClick="canelTimeBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/show_picker"
android:layout_centerHorizontal="true"
android:text="取消時間" />
</RelativeLayout>
在Java的部分,我連import都貼出來了,基本上照著做不會出問題。
在下方的code裡面我有下很多註解
如果還有不懂可以再提出
比較需要注意的事情是
1、SimpleDateFormat的使用,因為我只要抓取小時和分鐘,這邊只填上"HHmm"
2 、時間的相加減,其實都是用“毫秒”再作轉換
3、ProgressBar內的setMax和setProgress只能裝int,long轉換成int的方法我寫在下面
MainActivity.java
import android.app.TimePickerDialog;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.TimePicker;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private ProgressBar mProgressBar;
private TextView mPercentage;
private int progress = 0;//變化參數
private int hours, mins;
private Context mContext;
private TextView mShow;
private CountDownTimer countDownTimer;
private Button show_picker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
initView();
}
private void initView() {
show_picker = (Button) findViewById(R.id.show_picker);
mShow = (TextView) findViewById(R.id.show);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
mPercentage = (TextView) findViewById(R.id.progress_tv);
}
//設定時間的按鈕
public void timePickerBtn(View view) {
//防呆
show_picker.setClickable(true);
// //假如重複選擇時間,暫停上一個計時器
if (countDownTimer != null) {
countDownTimer.cancel();
countDownTimer.onFinish();
}
TimePickerDialog timepicker = new TimePickerDialog(mContext, onTimeSetListener, hours, mins, true);
timepicker.show();
}
//取消倒數
public void canelTimeBtn(View view) {
show_picker.setClickable(true);
mPercentage.setText("0%");
mProgressBar.setProgress(0);
progress = 0;
if (countDownTimer != null) {
countDownTimer.cancel();
countDownTimer.onFinish();
}
}
//TimePicker監聽
TimePickerDialog.OnTimeSetListener onTimeSetListener = new TimePickerDialog.OnTimeSetListener() {
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
//只format hours and mins
SimpleDateFormat sdf = new SimpleDateFormat("HHmm");
//抓取現在的時間
Calendar calendar = Calendar.getInstance();
int nowHours = calendar.get(Calendar.HOUR_OF_DAY);
int nowMins = calendar.get(Calendar.MINUTE);
Long time = null;
//確認格式是我們在SimpleDateFormat內指定的樣子"HHmm"
Log.d("checkpoint", " 確認選取的時間 = " + format(hourOfDay) + format(minute));
Log.d("checkpoint", "卻線線在的時間 = " + format(nowHours) + format(nowMins));
try {
//選取時間 - 現在時間
Date pickDate = sdf.parse(format(hourOfDay) + format(minute));
Date nowDate = sdf.parse(format(nowHours) + format(nowMins));
Long pickLongDate = pickDate.getTime();
Long nowLongDate = nowDate.getTime();
time = pickLongDate - nowLongDate;
//設定ProgressBar
mProgressBar.setMax(toIntExact(time));
Log.d("checkpoint", "checkpoint = " + time);
} catch (ParseException e) {
e.printStackTrace();
Log.d("checkpoint", "error - " + e);
}
if (time != null) {
//time為毫秒 帶入倒數計時器CountDownTimer
final Long finalTime = time;
countDownTimer = new CountDownTimer(finalTime, 500) {
@Override
public void onFinish() {
mShow.setText("Done!");
if (progress != 0) {
mPercentage.setText("100%");
mProgressBar.setProgress(toIntExact(finalTime));
} else {
mPercentage.setText("0%");
}
show_picker.setClickable(true);
}
@Override
public void onTick(long millisUntilFinished) {
//這方法中間如果遇到個位數字,前方自動補0 "08"
NumberFormat f = new DecimalFormat("00");
long hour = (millisUntilFinished / 3600000) % 24;
long min = (millisUntilFinished / 60000) % 60;
long sec = (millisUntilFinished / 1000) % 60;
//換算必須用Double,如果使用int不管怎麼除都會是0
progress = (int) ((Double.valueOf(finalTime - millisUntilFinished) / Double.valueOf(finalTime)) * 100);
//在計時器內對ProgrssBar做每秒的更新
mProgressBar.setProgress(toIntExact(finalTime - millisUntilFinished));
//設定旁邊的文字%
mPercentage.setText(progress + "%");
//設定倒數計時
mShow.setText(f.format(hour) + ":" + f.format(min) + ":" + f.format(sec));
}
}.start();
}
}
};
//重新把long變成String,中間如果遇到個位數字,前方自動補0 "08"
private String format(long value) {
String valueTwo = stringValue(value);
if (valueTwo.length() == 1) {
return "0" + valueTwo;
}
return valueTwo;
}
//轉換器long convert to String
private String stringValue(long value) {
return String.valueOf(value);
}
//轉換器 Long convert to int
public static int toIntExact(long value) {
if ((int) value != value) {
throw new ArithmeticException("integer overflow");
}
return (int) value;
}
}
歡迎提出討論喔!
DEMO:https://github.com/nikeru8/ProgressBarDemo/tree/IntegrationDemo



你好,我想請問一下,要怎麼樣才能把遇到個位數補08在前面的功能刪掉呢?
回覆刪除因為這樣在倒數計時的時候好像有點怪,假設設定倒數一分鐘的時候,會顯示剩下08:00:59(8小時1分鐘)
還是設計這樣功能是有什麼特殊的作用嗎?
在麻煩您,謝謝
不好意思回覆晚了。
刪除不太懂你的意思,能再詳細一點嗎