Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีใช้ DatePicker และ OnDateChangedListener ใน Android

ภาพรวม

DatePicker เป็น Widget สำหรับเลือกวันที่ (วัน/เดือน/ปี) มี 2 โหมด: Calendar View (API 11+) และ Spinner Mode (Classic) ใช้ OnDateChangedListener ฟังเหตุการณ์เมื่อผู้ใช้เปลี่ยนวันที่

XML Attributes สำคัญ

Attributeคำอธิบาย
android:calendarViewShowntrue/false แสดง Calendar View (API 11+)
android:spinnersShowntrue/false แสดง Spinner (Classic)
android:startYear / endYearจำกัดช่วงปี (Calendar Mode)
android:minDate / maxDateจำกัดวันที่ขั้นต่ำ/สูงสุด (millis since epoch)
android:dateTextAppearanceStyle สำหรับข้อความวันที่

ตัวอย่างพื้นฐาน: Calendar Mode + Listener

1. Layout (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <DatePicker
        android:id="@+id/datePicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:calendarViewShown="true"
        android:spinnersShown="false"
        android:startYear="2020"
        android:endYear="2030" />

    <TextView
        android:id="@+id/tvSelectedDate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/datePicker"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="24dp"
        android:text="วันที่ที่เลือก: -"
        android:textSize="18sp" />

</RelativeLayout>

2. MainActivity.java

package com.example.myapplication;

import android.os.Bundle;
import android.widget.DatePicker;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {

    private DatePicker datePicker;
    private TextView tvSelectedDate;
    private Calendar selectedDate = Calendar.getInstance();

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

        datePicker = findViewById(R.id.datePicker);
        tvSelectedDate = findViewById(R.id.tvSelectedDate);

        // ตั้งค่าวันที่เริ่มต้น (วันนี้)
        updateDisplay();

        // Listener: เรียกเมื่อผู้ใช้เปลี่ยนวันที่ (Calendar Mode)
        datePicker.setOnDateChangedListener((view, year, monthOfYear, dayOfMonth) -> {
            selectedDate.set(year, monthOfYear, dayOfMonth);
            updateDisplay();
            
            // Toast แจ้งเตือน (Optional)
            String msg = String.format(Locale.getDefault(), 
                "เปลี่ยนวันที่เป็น: %02d/%02d/%d", dayOfMonth, monthOfYear + 1, year);
            Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
        });
    }

    private void updateDisplay() {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy (EEEE)", Locale.getDefault());
        tvSelectedDate.setText("วันที่ที่เลือก: " + sdf.format(selectedDate.getTime()));
    }
}

ตัวอย่างขั้นสูง: Spinner Mode + Validation

<DatePicker
    android:id="@+id/datePickerSpinner"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:calendarViewShown="false"
    android:spinnersShown="true"
    android:minDate="@{@long/minDateMillis}"  // Data Binding
    android:maxDate="@{@long/maxDateMillis}" />

// ใน Code: ตั้งค่า min/max Date ด้วยโค้ด
Calendar minCal = Calendar.getInstance();
minCal.add(Calendar.YEAR, -100); // 100 ปีก่อน
datePicker.setMinDate(minCal.getTimeInMillis());

Calendar maxCal = Calendar.getInstance();
maxCal.add(Calendar.YEAR, 10); // 10 ปีข้างหน้า
datePicker.setMaxDate(maxCal.getTimeInMillis());

DatePickerDialog (Dialog แบบ Floating - แนะนำสำหรับ Form)

แทนที่จะวาง DatePicker ใน Layout ตรงๆ มักนิยมใช้ Dialog:

// ใน onClick ของ EditText หรือ Button
DatePickerDialog dialog = new DatePickerDialog(
    this,
    (view, year, month, dayOfMonth) -> {
        Calendar cal = Calendar.getInstance();
        cal.set(year, month, dayOfMonth);
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault());
        editText.setText(sdf.format(cal.getTime()));
    },
    calendar.get(Calendar.YEAR),
    calendar.get(Calendar.MONTH),
    calendar.get(Calendar.DAY_OF_MONTH)
);
dialog.show();

// ตั้งค่า Min/Max Date สำหรับ Dialog (API 24+)
dialog.getDatePicker().setMinDate(minDateMillis);
dialog.getDatePicker().setMaxDate(maxDateMillis);

Material Date Picker (Modern - แนะนำใหม่)

Material Components มี Date Picker ใหม่ที่สวยงาม รองรับ Range Selection:

// build.gradle
implementation 'com.google.android.material:material:1.11.0'

// ใช้งาน
MaterialDatePicker picker = MaterialDatePicker.Builder.datePicker()
    .setTitleText("เลือกวันที่")
    .setSelection(MaterialDatePicker.todayInUtcMilliseconds())
    .build();

picker.addOnPositiveButtonClickListener(selection -> {
    String date = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault())
        .format(new Date(selection));
    textView.setText(date);
});

picker.show(getSupportFragmentManager(), "DATE_PICKER");

การจัดการ Locale และ Timezone

  • DatePicker ใช้ Locale ของ Device อัตโนมัติ
  • Calendar.MONTH เริ่มจาก 0 (January = 0) → ต้อง +1 เมื่อแสดงผล
  • ใช้ Locale.getDefault() หรือ Locale เฉพาะ (new Locale("th", "TH")) สำหรับการ Format
  • สำหรับ Timezone: ใช้ Calendar/Date ปกติ (Local Time) หรือ Instant/ZonedDateTime (Java 8+ API 26+)

สรุป

  • DatePicker: Widget ใน Layout, 2 โหมด (Calendar/Spinner)
  • OnDateChangedListener: ฟังการเปลี่ยนแปลง (Calendar Mode)
  • DatePickerDialog: Dialog แบบ Floating, ใช้ใน Form (แนะนำ)
  • MaterialDatePicker: UI ทันสมัย, รองรับ Range, Themeable (แนะนำโปรเจกต์ใหม่)
  • จำกัดวันที่ได้ด้วย minDate/maxDate หรือ startYear/endYear