前言:
前陣子收到一個問題。其實收到問題的當下就想到怎麼做了,順便實作一下吧!
其實這三個東西感覺自己都會,整合起來就會卡卡的,可能就像英文一樣吧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分鐘)
還是設計這樣功能是有什麼特殊的作用嗎?
在麻煩您,謝謝
不好意思回覆晚了。
刪除不太懂你的意思,能再詳細一點嗎