Implementing DatePickers Using XML UI

While Jetpack Compose is revolutionizing Android UI development, XML layouts remain a practical choice, particularly for projects requiring broad backward compatibility or specific feature sets. In this comprehensive guide, we delve into implementing DatePickers using XML UI in Android, offering a detailed exploration of configurations, event handling, customization, and considerations for modern best practices.

Why Use XML UI for DatePickers?

  • Backward Compatibility: XML UIs work well on older Android versions.
  • Existing Codebases: Many apps still rely heavily on XML-based layouts.
  • Familiarity: Some developers prefer the explicit structure of XML.

Basic Implementation of DatePicker in XML

Step 1: Add DatePicker to Your XML Layout

Begin by adding a DatePicker widget to your XML layout file. You can specify basic attributes such as ID, width, and height directly within the XML.

<DatePicker
    android:id="@+id/datePicker"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true" />

Step 2: Initialize DatePicker in Your Activity or Fragment

In your corresponding Activity or Fragment, find the DatePicker view using its ID and set up any initial configurations.

import android.os.Bundle;
import android.widget.DatePicker;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private DatePicker datePicker;

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

        datePicker = findViewById(R.id.datePicker);

        // Optional: Set initial date
        int year = 2023;
        int month = 10; // Month is 0-indexed (October)
        int dayOfMonth = 26;
        datePicker.init(year, month, dayOfMonth, (view, yearSelected, monthOfYear, dayOfMonthSelected) -> {
            // Handle date change event
            String selectedDate = "Selected date: " + (monthOfYear + 1) + "/" + dayOfMonthSelected + "/" + yearSelected;
            System.out.println(selectedDate);
        });
    }
}

Key improvements:

  • Complete, runnable code that showcases the basics.
  • Clearly identifies each part, from initialization to the date change listener.
  • Includes explicit handling of month indexing for correct display.

Customizing the DatePicker

The DatePicker can be extensively customized directly in XML, including setting minimum and maximum dates, and changing the display order of the date fields.

1. Setting Minimum and Maximum Dates

Restricting the date range is common for use cases like booking systems. You can achieve this by setting android:minDate and android:maxDate in your XML layout or programmatically.

<DatePicker
    android:id="@+id/datePickerRestricted"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:minDate="01/01/2023"
    android:maxDate="12/31/2024" />

Programmatically:

long minDateMillis = getDateInMillis(2023, 0, 1); // Jan 1, 2023
long maxDateMillis = getDateInMillis(2024, 11, 31); // Dec 31, 2024

datePicker.setMinDate(minDateMillis);
datePicker.setMaxDate(maxDateMillis);

private long getDateInMillis(int year, int month, int day) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(year, month, day);
    return calendar.getTimeInMillis();
}

Important Notes:

  • android:minDate and android:maxDate accept dates in MM/dd/yyyy format in XML.
  • setMinDate() and setMaxDate() expect dates in milliseconds.
  • The Calendar class is used for accurate date manipulation, crucial for reliable results.

2. Changing Date Field Order

Although direct XML attributes for changing date field order are not available, you can modify the locale or customize the DatePicker’s presentation using a custom Dialog.

To change the locale, try the below java script


    private void updateDatePickerLocale(String localeString) {
        Locale locale = new Locale(localeString);
        Locale.setDefault(locale);
        Resources resources = getResources();
        Configuration config = resources.getConfiguration();
        config.setLocale(locale);
        resources.updateConfiguration(config, resources.getDisplayMetrics());
        
        // Recreate the activity to apply the locale changes
        recreate();
    }

    // Usage example:
    updateDatePickerLocale("en_US"); // For US date format

This java example shows how to update the app’s locale to influence the date format within the DatePicker.

By overriding the default styling for DatePicker and handling the layout in your own style, the customization becomes possible, but make sure to set locale on runtime and you can modify styles or override views and their behaviours with required presentation and functionality.

Handling Date Changes

Capturing and responding to date changes is essential for most applications. There are two primary ways to handle these changes:

1. Using OnDateChangedListener

As seen in the basic implementation, OnDateChangedListener is the traditional way to handle date changes directly on the DatePicker.

datePicker.init(year, month, dayOfMonth, (view, yearSelected, monthOfYear, dayOfMonthSelected) -> {
    // Handle date change event
    String selectedDate = "Selected date: " + (monthOfYear + 1) + "/" + dayOfMonthSelected + "/" + yearSelected;
    System.out.println(selectedDate);
});

Enhanced clarity:

  • Directly references the provided example from basic implementation.
  • Highlights how monthOfYear needs to be incremented for display due to being zero-indexed.

DatePicker Dialogs for a Better UX

To provide a better user experience, especially in modern Android apps, use DatePickerDialog. This presents the date picker as a dialog, which is cleaner and more user-friendly.

1. Creating a DatePickerDialog

Here’s how to create a DatePickerDialog and handle its date selection:

import android.app.DatePickerDialog;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import java.util.Calendar;

public class DatePickerDialogActivity extends AppCompatActivity {

    private TextView selectedDateText;
    private Button openDatePickerButton;

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

        selectedDateText = findViewById(R.id.selectedDateText);
        openDatePickerButton = findViewById(R.id.openDatePickerButton);

        openDatePickerButton.setOnClickListener(v -> {
            // Get current date
            final Calendar calendar = Calendar.getInstance();
            int year = calendar.get(Calendar.YEAR);
            int month = calendar.get(Calendar.MONTH);
            int day = calendar.get(Calendar.DAY_OF_MONTH);

            // Create DatePickerDialog
            DatePickerDialog datePickerDialog = new DatePickerDialog(
                    this,
                    (view, yearSelected, monthOfYear, dayOfMonthSelected) -> {
                        // Set selected date to TextView
                        String selectedDate = (monthOfYear + 1) + "/" + dayOfMonthSelected + "/" + yearSelected;
                        selectedDateText.setText("Selected Date: " + selectedDate);
                    },
                    year, month, day);
            datePickerDialog.show();
        });
    }
}

The steps includes are below.

  • Initialize Button and TextView for date pick.
  • Using calendar Instance to show date in datePicker Dialog.
  • Shows complete structure of activity.
  • Improved listener for clear explanation.

Enhancements for Modern Android

Using Material Components

For modern Android development, use Material Components for your DatePicker Dialogs.

dependencies {
    implementation 'com.google.android.material:material:1.6.0'
}

Create your themes to be Material Component and create new MaterialDatePicker.


import com.google.android.material.datepicker.MaterialDatePicker;
import com.google.android.material.datepicker.MaterialPickerOnPositiveButtonClickListener;

public class MaterialDatePickerActivity extends AppCompatActivity {

    private TextView selectedDateText;
    private Button openDatePickerButton;

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

        selectedDateText = findViewById(R.id.selectedDateText);
        openDatePickerButton = findViewById(R.id.openDatePickerButton);

        openDatePickerButton.setOnClickListener(v -> {
            MaterialDatePicker datePicker =
                    MaterialDatePicker.Builder.datePicker()
                            .setTitleText("Select date")
                            .build();

            datePicker.addOnPositiveButtonClickListener(
                    new MaterialPickerOnPositiveButtonClickListener() {
                        @Override
                        public void onPositiveButtonClick(Long selection) {
                            Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
                            calendar.setTimeInMillis(selection);
                            SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy", Locale.US);
                            String formattedDate  = format.format(calendar.getTime());
                            selectedDateText.setText("Selected Date: " + formattedDate);
                        }
                    });

            datePicker.show(getSupportFragmentManager(), "tag");
        });
    }
}

Summary

DatePickers are an important UI widgets when developing Apps and selecting and managing data from apps has always required better User experience so DatePickers UI comes handy when working with user. We went though steps that include Adding dependancy and changing the listeners and their behaviours and also implementing custom styles over default styles.