Day 11 : DatePicker

Day 11 : DatePicker Cover Image

สวัสดีครับ บทความนี้เป็นบทความที่ 11 แล้วนะครับ ที่ผมจะมาเขียน ในซีรีย์ Learn 30 Android Libraries in 30 days

สำหรับบทความทั้งหมด อ่านได้จากด้านล่างครับ

วันนี้ขอนำเสนอ DateTimePicker ครับ ต้องขอขอบคุณ คุณเอก ที่แนะนำมาครับ

DateTimePicker คืออะไร?

DatePicker ตัวนี้เป็นคนละตัวกับ DatePickerDialog ของทาง Android นะครับ ซึ่ง Library ตัวนี้จะเอาไว้ปรับแต่งให้หน้าตา DatePicker และ TimePicker ให้มีหน้าตาสวยงามขึ้นนะครับ ส่วนลักษณะการทำงาน วิธีการเรียกใช้ แทบเหมือนกันเลย

Installation

ขั้นตอนแรก ทำการติดตั้ง dependencies เปิดไฟล์ build.gradle จากนั้นเพิ่มโค๊ดนี้ลงไป

dependencies {
    compile 'com.github.flavienlaurent.datetimepicker:library:0.0.1'
}

กด Sync Gradle (ปัจจุบัน เวอร์ชัน 0.0.1)

Getting Started

ก่อนที่จะไปเริ่มสร้างโปรเจ็ค เรามารู้จักกับ DateTimePicker เบื้องต้นกันก่อนดีกว่า ตัว DateTimePicker จะมี Dialog อยู่ 2 แบบ นั่นก็คือ Dialog แบบ DatePicker และแบบ TimePicker

DatePicker

เป็น Dialog ที่เอาไว้เลือก วัน/เดือน/ปี เช่น วันเกิด วันปัจจุบัน เป็นต้น สำหรับการใช้งาน DatePicker เราจะใช้คลาส DatePickerDialog วิธีการสร้าง ก็มีดังนี้

  1. ทำการสร้าง new instance ของ DatePickerDialog ขึ้นมา โดย set ค่า default ลงไป
  2. ทำการ implement DatePickerDialog.OnDateSetListener เพื่อเอาไว้รับค่าเมื่อยูเซอร์กดเลือก วัน เสร็จแล้ว ก็จะส่ง callback กลับ

TimePicker

เหมือนกับ Dialog ด้านบน แต่ต่างกันที่ TimePicker จะเป็นการเลือก เวลา แทนที่จะเป็น วัน เดือน ปี การแสดง TimePicker เราจะใช้คลาส TimePickerDialog วิธีสร้าง ก็มีดังนี้

  1. ทำการสร้าง new instance ของ TimePickerDialog ขึ้นมา
  2. ทำการ implement interface TimePickerDialog.OnTimeSetListener เป็น Listener เพื่อเอาไว้รับค่า callback

Create new Project

เริ่มสร้างโปรเจ็ค ผมจะใช้ไฟล์ 2 ไฟล์เช่นเคย คือ DateTimePickerActivity และ activity_datetime_picker.xml ในส่วนของเลเอาท์ จะมี Button สำหรับกดเลือก DatePicker และ TimePicker ขึ้นมาแสดง เมื่อเลือกแล้ว ก็จะแสดง วันที่/เวลาที่เลือก ลงบน TextView ที่กำหนดไว้ เพราะฉะนั้นเลเอาท์ จะได้ประมาณนี้

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:padding="16dp">

    <RelativeLayout android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true">

        <TextView android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:gravity="center"
                  android:textSize="24sp"
                  android:textColor="#ff0071ff"
                  android:id="@+id/text_date"
                  android:layout_alignParentTop="true"
                  android:layout_alignParentLeft="true"
                  android:layout_alignParentStart="true"/>
        <Button
            android:id="@+id/button_date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/select_date"
            android:layout_below="@+id/text_date"
            android:layout_centerHorizontal="true"/>


        <TextView android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:textSize="24sp"
                  android:textColor="#ffee1789"
                  android:id="@+id/text_time"
                  android:layout_marginTop="64dp"
                  android:gravity="center"
                  android:layout_below="@+id/button_date"
                  android:layout_alignParentLeft="true"
                  android:layout_alignParentStart="true"/>

        <Button
            android:id="@+id/button_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/select_time"
            android:layout_toEndOf="@+id/text_time"
            android:layout_below="@+id/text_time"
            android:layout_alignLeft="@+id/button_date"
            android:layout_alignStart="@+id/button_date"/>

    </RelativeLayout>

</RelativeLayout>

ต่อมาที่ไฟล์ DateTimePicker.java ผมสร้างมันขึ้นมา แล้วทำการ binding View ต่างๆ แบบนี้ ส่วน Calendar เอาไว้สำหรับแสดงเวลาปัจจุบันครับ

package com.devahoy.learn30androidlibraries.day11;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.devahoy.learn30androidlibraries.R;
import com.fourmob.datetimepicker.date.DatePickerDialog;
import com.sleepbot.datetimepicker.time.RadialPickerLayout;
import com.sleepbot.datetimepicker.time.TimePickerDialog;

import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;

public class DateTimePickerActivity extends ActionBarActivity {

    private DatePickerDialog mDatePicker;
    private TimePickerDialog mTimePicker;

    private Calendar mCalendar;

    private Button mTimeButton;
    private Button mDateButton;
    private TextView mTextTime;
    private TextView mTextDate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.day11_activity_date_picker);

        mTimeButton = (Button) findViewById(R.id.button_time);
        mDateButton = (Button) findViewById(R.id.button_date);
        mTextTime = (TextView) findViewById(R.id.text_time);
        mTextDate = (TextView) findViewById(R.id.text_date);

        mCalendar = Calendar.getInstance();
    }
}

สังเกตว่า ต้อง import ให้ถูกด้วยนะครับ คนละตัวกับ default ของ android ที่ถูกต้องเป็น

import com.fourmob.datetimepicker.date.DatePickerDialog;
import com.sleepbot.datetimepicker.time.TimePickerDialog;

ต่อมาผมทำการสร้าง DatePickerDialog ขึ้นมา โดยกำหนดค่าเริ่มต้นให้กับ Dialog ว่าจะเซทเป็นวันที่เท่าไหร่ ตามนี้

mDatePicker = DatePickerDialog.newInstance(onDateSetListener,
        mCalendar.get(Calendar.YEAR),       // ปี
        mCalendar.get(Calendar.MONTH),      // เดือน
        mCalendar.get(Calendar.DAY_OF_MONTH),// วัน (1-31)
        false);                             // ให้สั่นหรือไม่?

ต่อมาสร้าง TimePickerDialog ขึ้นมา และกำหนดค่าเริ่มต้นให้มันดังนี้ โดยกำหนดเวลาเป็น 10.30 น. ในระบบ 24-Hr

mTimePicker = TimePickerDialog.newInstance(onTimeSetListener,
        10,     // หน่วยเข็มชั่วโมง
        30,     // เข็มนาที
        true,   // ใช้ระบบนับแบบ 24-Hr หรือไม่? (0 - 23 นาฬิกา)
        false); // ให้สั่นหรือไม่?

หากคุณตั้งค่า vibrate ้ต้องไปทำการตั้ง permission ที่ไฟล์ AndroidManifest.xml ด้วยนะครับ

<uses-permission android:name="android.permission.VIBRATE" />

จะเห็นได้ว่า ทั้งสองด้านบนที่ผมสร้างมี error? เนื่องจากว่า onDateSetListener กับ onTimeSetListener มันคืออะไร?

มันคือ Listener ที่จะเอาไว้รับค่าสำหรับส่ง Listener กลับมา ทำได้ โดยการให้ Activity ทำการ implement แล้วก็ override เมธอด onDateSet() และ onTimeSet() หรืออีกวิธีนึง ก็สร้าง Interface ขึ้นมาใหม่ก็ได้ ในที่นี้ผมใช้วิธีสร้าง Interface ขึ้นมาใหม่ ดังนี้

private TimePickerDialog.OnTimeSetListener onTimeSetListener =
        new TimePickerDialog.OnTimeSetListener() {
    @Override
    public void onTimeSet(RadialPickerLayout radialPickerLayout, int hourOfDay, int minute) {
        mTextTime.setText(" " + hourOfDay + " : " + minute);
    }
};

private DatePickerDialog.OnDateSetListener onDateSetListener =
        new DatePickerDialog.OnDateSetListener() {
    @Override
    public void onDateSet(DatePickerDialog datePickerDialog, int year, int month, int day) {

        DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.LONG);
        mCalendar.set(year, month, day);
        Date date = mCalendar.getTime();
        String textDate = dateFormat.format(date);

        mTextDate.setText(textDate);
    }
};

ด้านบนไม่มีอะไรมาก เพียงแค่ เมื่อผู้ใช้กดเลือกแล้ว ก็จะ set ค่าไปที่ TextView ครับ ส่วน DatePickerDialog มีการใช้ DateFormat มาช่วยในการจัดฟอแมตเฉยๆครับ

เมื่อเราทำ Dialog เสร็จแล้ว ขั้นตอนต่อไป ก็สั่งให้มันโชว์ เมื่อมีการกดปุ่ม ฉะนั้น ก็เพิ่ม setOnClickListener ให้กับปุ่มทั้งสองดังนี้

mTimeButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mTimePicker.show(getSupportFragmentManager(), "timePicker");
    }
});

mDateButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mDatePicker.setYearRange(2000, 2020);
        mDatePicker.show(getSupportFragmentManager(), "datePicker");
    }
});

โดยด้านบน TimePickerDialog ทำการโชว์ โดยรับ parameter เป็น Fragment และ String (ตั้งชื่ออะไรก็ได้ เอาไว้ใช้ระบุตัว เวลา implement พวก Fragment Transaction หากไม่ได้ใช้ ก็ใส่ไรไปก็ได้ครับ)

ส่วน DatePickerDialog ทำการเสร็จ range ของปี ว่าจะให้เลือกได้ระหว่างปีอะไรถึงปีอะไร ต่อมาก็สั่งโชว์เหมือนกันเลย

สุดท้าย ทดสอบรันโปรแกรม จะได้หน้าตาแบบนี้

S

s2

ss

ลองเล่นกันดูนะครับ

สรุป

หลังจากที่ลองเล่นแล้วรู้สึกว่า มันแทบจะเหมือนกับ Picker ที่เป็น Default ของ Android เลย ต่างกันที่หน้าตา ดีไซน์เท่านั้นครับ สำหรับใครที่อยากเปลี่ยนหน้าตา Dialog ให้ดูสวยงาม ก็แนะนำ ลองเอาอันนี้ไปเล่นกันดูนะครับ :D

Chai

Chai Phonbopit : Developer แห่งหนึ่ง • ผู้ชายธรรมดาๆ ที่ชื่นชอบ Node.js, JavaScript และ Open Source มีงานอดิเรกเป็น Acoustic Guitar และ Football

บทความล่าสุด