首先抱怨一下,Android Developers網站又改版了…

先學習相關的知識:Android上日期與時間的處理

在APP UI上要取得或是設定時間和日期最方便的方式就是使用TimePickerDialogDatePickerDialog了。Google建議我們以DialogFragment為基礎來建置各種對話方塊(Dialog)。使用DialogFragment來建置日期和時間的挑選器相關的說明與範例程式碼可以參考這裡

因為上面介紹的程式碼太過於繁雜,對於每一個對話框都需要建立一個java程式類別,對於物件導向程式基礎不好的人來說難以處理。所以在教學上我們用直接呼叫TimePickerDialog和DatePickerDialog的方式來介紹這兩個元件,先理解元件的使用,等基礎好一些以後再轉換成獨立的DialogFragment。

程式說明與範例:

我們希望點擊日期欄位的時候可以呼叫DatePickerDialog或是TimePickerDialog,設定日期與時間。

// 簡化版的程式,只剩下與日期相關的部分
package cycu.nclab.example.accounting2018;

import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.TimePicker;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;

public class Bookkeeping2 extends AppCompatActivity implements View.OnClickListener {

    TextView mDate, mTime;

    SimpleDateFormat df_date = new SimpleDateFormat("yyyy/MM/dd",
            Locale.getDefault());
    SimpleDateFormat df_time_am = new SimpleDateFormat("hh a",
            Locale.US);

    Calendar c;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bookkeeping_constraint_layout);

        mDate = this.findViewById(R.id.textView7);
        mTime = this.findViewById(R.id.textView8);
    }

    @Override
    protected void onStart() {
        super.onStart();

        c = Calendar.getInstance(); // 取得目前日期與時間
        /*
        這行是一個隱式宣告,事實上是new了一個新的Calendar物件。
        關於c = Calendar.getInstance到底要寫在onCreate()還是onStart()各有優劣。
        寫在onCreate()裡面可以讓c的生命週期一直延續到onDestroy(),不需要去recheck c裡面的內容;

        寫在onStart()裡面則是每一次從背景被翻出來就產生一個新的物件,同時就需要對新的物件的內容(初值)
        做檢查與設定。同時這樣並沒有節省記憶體空間,如果我們沒有在onStop()主動釋放掉c的話,這個物件
        還是會被保留在記憶體中,然而在onStart()時建立新物件的時候,舊物件則被Garbage Collector回收。

        但是,在某幾次的經驗,如果APP被放到背景太久,OS有機會會去回收部分APP使用的資源,但又不回收整個
        APP。這會讓APP重新回到onStart()的時候c變成一個未定義的狀態而產生系統錯誤。因此我個人的習慣是
        在onStart()的時候重新整理所有的變數,檢查其數值是否正確。
         */
        setListener();
        initVarable();
    }

    @Override
    protected void onStop() {
        releaseListener();
        super.onStop();
    }


    private void setListener() {
        mDate.setOnClickListener(this);
        mTime.setOnClickListener(this);
    }

    private void releaseListener() {
        mDate.setOnClickListener(null);
        mTime.setOnClickListener(null);
    }

    private void initVarable() {
        // 顯示目前時間
        mDate.setText(df_date.format(c.getTime()));
        mTime.setText(df_time_am.format(c.getTime()));
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.textView7:
                // on Date
                new DatePickerDialog(this,
                        new DatePickerDialog.OnDateSetListener() {
                     @Override
                     public void onDateSet(DatePicker view, int year,
                                                  int monthOfYear, int dayOfMonth) {
                                c.set(Calendar.YEAR, year);
                                c.set(Calendar.MONTH, monthOfYear);
                                c.set(Calendar.DAY_OF_MONTH, dayOfMonth);
                        // 將日期寫入日期欄位
                                mDate.setText(df_date.format(c.getTime()));
                     }
                  }, c.get(Calendar.YEAR), c.get(Calendar.MONTH),
                  c.get(Calendar.DAY_OF_MONTH)).show();
                break;
            case R.id.textView8:
                // on Time
                new TimePickerDialog(this,
                        new TimePickerDialog.OnTimeSetListener() {
                            @Override
                            public void onTimeSet(TimePicker view, int hourOfDay,
                                                  int minute) {
                                c.set(Calendar.HOUR_OF_DAY, hourOfDay);
                                c.set(Calendar.MINUTE, minute);
                                mTime.setText(df_time_am.format(c.getTime()));
                            }
                        }, c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE),
                        false).show();
                break;
        }
    }
}

這兩個欄位是使用TextView來製作的,所以我們在line 23定義兩個TextView參照(reference)。

line 37, 38利用findViewById()將物件指定給參照。

在onStart()的時候註冊監聽,在onStop()的時候取消監聽。

 

line 25-28定義日期和時間想要顯示的格式。

line 30 宣告一個日期參照c。

line 45 new一個新的Calendar 物件。然後在line 60行呼叫變數初始化,顯示目前的日期與時間到UI上。

line81和82的操作可以這樣解釋:由日曆物件中取出日期和時間,然後交給df_date物件將日期和時間轉換成預定的字串的形式,最後使用mDate的setText方法將字串顯示在UI上。

line 91~103為日期設定,line 107~117為時間設定,這裡反而最簡單,就是拷貝+貼上

每個Android版的的Picker都長得不太一樣,可以用模擬器測試不同版本是否能夠正常執行。

發佈留言