Android 4
8. DatePicker, TimePicker, and Clocks
This chapter
A DatePicker is a widget that allows the user to select a month, day and year.
java.lang.Object -> android.view.View ->
android.view.ViewGroup -> android.widget.FrameLayout
-> android.widget.DatePicker.
The code below is mostly from
http://developer.android.com/resources/tutorials/views/hello-datepicker.html.
Layout file, main.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/dateDisplay" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=""/> <Button android:id="@+id/pickDate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/change_date"/> </LinearLayout>
and the strings.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World< MyDatePickerActivity!</string> <string name="app_name">MyDatePicker</string> <string name="change_date">Change the date</string> </resources>
For the layout, we're using a vertical LinearLayout, with a TextView that will display the date and a Button that will initiate the DatePicker dialog. With this layout, the TextView will sit above the Button. The text value in the TextView is set empty, as it will be filled with the current date when our Activity runs.
Java code, myDatePicker.java:
package com.bogotobogo.MyDatePicker; import java.util.Calendar; import android.app.Activity; import android.app.DatePickerDialog; import android.app.Dialog; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.DatePicker; import android.widget.TextView; public class MyDatePickerActivity extends Activity { private TextView mDateDisplay; private Button mPickDate; private int mYear; private int mMonth; private int mDay; static final int DATE_DIALOG_ID = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // capture our View elements mDateDisplay = (TextView) findViewById(R.id.dateDisplay); mPickDate = (Button) findViewById(R.id.pickDate); // add a click listener to the button mPickDate.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { showDialog(DATE_DIALOG_ID); } }); // get the current date final Calendar c = Calendar.getInstance(); mYear = c.get(Calendar.YEAR); mMonth = c.get(Calendar.MONTH); mDay = c.get(Calendar.DAY_OF_MONTH); // display the current date (this method is below) updateDisplay(); } @Override protected Dialog onCreateDialog(int id) { switch (id) { case DATE_DIALOG_ID: return new DatePickerDialog(this, mDateSetListener, mYear, mMonth, mDay); } return null; } // updates the date we display in the TextView private void updateDisplay() { mDateDisplay.setText( new StringBuilder() // Month is 0 based so add 1 .append(mMonth + 1).append("-") .append(mDay).append("-") .append(mYear).append(" ")); } // the callback received when the user "sets" the date in the dialog private DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() { public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { mYear = year; mMonth = monthOfYear; mDay = dayOfMonth; updateDisplay(); } }; }
Let's look at the code.
We start by instantiating variables for our Views and date fields. The DATE_DIALOG_ID is a static integer that uniquely identifies the Dialog.
In the onCreate() method, we get prepared by setting the layout and capturing the View elements.
mDateDisplay = (TextView) findViewById(R.id.dateDisplay); mPickDate = (Button) findViewById(R.id.pickDate);
Then we create an on-click listener for the Button, so that when it is clicked it will show our DatePicker dialog. The showDialog() method will pop-up the date picker dialog by calling the onCreateDialog() callback method.
mPickDate.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { showDialog(DATE_DIALOG_ID); } });
We then create an instance of Calendar and get the current year, month and day. Finally, we call updateDisplay() from our own method (defined later) that will fill the TextView.
final Calendar c = Calendar.getInstance(); mYear = c.get(Calendar.YEAR); mMonth = c.get(Calendar.MONTH); mDay = c.get(Calendar.DAY_OF_MONTH); updateDisplay();
Next, onCreateDialog() callback method.
This method is called by showDialog() and it is passed the identifier we gave showDialog() and initializes the DatePicker to the date we retrieved from our Calendar instance.
@Override protected Dialog onCreateDialog(int id) { switch (id) { case DATE_DIALOG_ID: return new DatePickerDialog(this, mDateSetListener, mYear, mMonth, mDay); } return null; }
The updateDisplay() method uses the member date values to write the date to our TextView.
private void updateDisplay() { mDateDisplay.setText( new StringBuilder() // Month is 0 based so add 1 .append(mMonth + 1).append("-") .append(mDay).append("-") .append(mYear).append(" ")); }
This OnDateSetListener() method listens for when the user is done setting the date (clicks the "Set" button). At that time, this fires and we update our member fields with the new date defined by the user and update our TextView by calling updateDisplay().
private DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() { public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { mYear = year; mMonth = monthOfYear; mDay = dayOfMonth; updateDisplay(); } };
Time to run our application.
We'll get something like this:
A TimePicker is a widget that allows the user to select the time by hour, minute and AM or PM.
Layout file:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/timeDisplay" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=""/> <Button android:id="@+id/pickTime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/change_time"/> </LinearLayout>
with strings.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World< MyTimePickerActivity!</string> <string name="app_name">MyTimePicker</string> <string name="change_time">Change the time</string> </resources>
For the layout, we're using a vertical LinearLayout, with a TextView that will display the time and a Button that will initiate the TimePicker dialog. With this layout, the TextView will sit above the Button. The text value in the TextView is set empty, as it will be filled by our Activity with the current time.
Our Java code, myTimePicker.java:
package com.bogotobogo.myTimePicker; import java.util.Calendar; import android.app.Activity; import android.app.Dialog; import android.app.TimePickerDialog; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.TimePicker; public class myTimePicker extends Activity { /** Called when the activity is first created. */ private TextView mTimeDisplay; private Button mPickTime; private int mHour; private int mMinute; static final int TIME_DIALOG_ID = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // capture our View elements mTimeDisplay = (TextView) findViewById(R.id.timeDisplay); mPickTime = (Button) findViewById(R.id.pickTime); // add a click listener to the button mPickTime.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { showDialog(TIME_DIALOG_ID); } }); // get the current time final Calendar c = Calendar.getInstance(); mHour = c.get(Calendar.HOUR_OF_DAY); mMinute = c.get(Calendar.MINUTE); // display the current date updateDisplay(); } @Override protected Dialog onCreateDialog(int id) { switch (id) { case TIME_DIALOG_ID: return new TimePickerDialog(this, mTimeSetListener, mHour, mMinute, false); } return null; } // updates the time we display in the TextView private void updateDisplay() { mTimeDisplay.setText( new StringBuilder() .append(pad(mHour)).append(":") .append(pad(mMinute))); } // the callback received when the user "sets" the time in the dialog private TimePickerDialog.OnTimeSetListener mTimeSetListener = new TimePickerDialog.OnTimeSetListener() { public void onTimeSet(TimePicker view, int hourOfDay, int minute) { mHour = hourOfDay; mMinute = minute; updateDisplay(); } }; private static String pad(int c) { if (c >= 10) return String.valueOf(c); else return "0" + String.valueOf(c); } }
We start by instantiating variables for our View elements and time fields. The TIME_DIALOG_ID is a static integer that uniquely identifies the dialog.
In the onCreate() method, we get prepared by setting the layout and capturing the View elements. We then set an on-click listener for the Button, so that when it is clicked, it will show our TimePicker dialog. The showDialog() method will perform a callback to our Activity.
setContentView(R.layout.main); // capture our View elements mTimeDisplay = (TextView) findViewById(R.id.timeDisplay); mPickTime = (Button) findViewById(R.id.pickTime); // add a click listener to the button mPickTime.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { showDialog(TIME_DIALOG_ID); } });
We then create an instance of Calendar and get the current hour and minute. Finally, we call updateDisplay() from our own method that will fill the TextView with the time.
// get the current time final Calendar c = Calendar.getInstance(); mHour = c.get(Calendar.HOUR_OF_DAY); mMinute = c.get(Calendar.MINUTE); // display the current date updateDisplay();
The onCreateDialog() callback method is passed the identifier we gave showDialog() and initializes the TimePicker to the time we retrieved from our Calendar instance. It will be called by showDialog().
@Override protected Dialog onCreateDialog(int id) { switch (id) { case TIME_DIALOG_ID: return new TimePickerDialog(this, mTimeSetListener, mHour, mMinute, false); } return null; }
The method, updateDisplay(), simply takes our member fields for the time and inserts them in the mTimeDisplay TextView. Note that we call a new method, pad(), on the hour and minute.
// updates the time we display in the TextView private void updateDisplay() { mTimeDisplay.setText( new StringBuilder() .append(pad(mHour)).append(":") .append(pad(mMinute))); }
Now when the user is done setting the time (clicks the "Set" button), we update our member fields with the new time and update our TextView.
// the callback received when the user "sets" the time in the dialog private TimePickerDialog.OnTimeSetListener mTimeSetListener = new TimePickerDialog.OnTimeSetListener() { public void onTimeSet(TimePicker view, int hourOfDay, int minute) { mHour = hourOfDay; mMinute = minute; updateDisplay(); } };
The pad() method that we called from the updateDisplay() returns the appropriate String representation of the hour or minute. It will prefix a zero to the number if it's a single digit.
private static String pad(int c) { if (c >= 10) return String.valueOf(c); else return "0" + String.valueOf(c); }
Run it and we'll get:
Displaying time is really easy.
Generated Java code
package com.bogotobogo.Clocks; import android.app.Activity; import android.os.Bundle; public class Clocks extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }
and the layout below will make AnalogClock and DigitalClock.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <AnalogClock android:id="@+id/analog" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_alignParentTop="true"/> <DigitalClock android:id="@+id/digital" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_below="@id/analog"/> </RelativeLayout>
Chronometer class that implements a simple timer. We can give it a start time in the elapsedRealtime() timebase, and it counts up from that, or if we don't give it a base time, it will use the time at which we call start(). By default it will display the current timer value in the form "MM:SS" or "H:MM:SS", or we can use setFormat(String) to format the timer value into an arbitrary string.
Java code:
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization