2010年1月29日金曜日

[Android] Custom Component - DateTimePicker


DatePickerとTimePickerを利用したDateTimePickerというのを作ってみた。

作った理由は何故かDatePickerとTimePickerは存在するのに、
日付と時間を両方設定できるコンポーネントが見つからないからだ。実はあるのか?
別にCustomコンポーネントの作り方の勉強にもなると思ったので作ってみよう。

レイアウト [res/layout/datetime_picker.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" android:gravity="center">
<DatePicker android:id="@+id/_babukuma_datetime_picker_date_picker"
android:layout_width="wrap_content" android:layout_height="wrap_content"></DatePicker>
<CheckBox android:id="@+id/_babukuma_datetime_picker_enable_time"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="enable Time"></CheckBox>
<TimePicker android:id="@+id/_babukuma_datetime_picker_time_picker"
android:layout_width="wrap_content" android:layout_height="wrap_content"></TimePicker>
</LinearLayout>


次は必要かと思われるアトリビュートを定義(とりあえずはこれぐらいかな) [res/values/attrs.xml]

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="DataTimePicker">
<attr name="enableTime" format="boolean" />
<attr name="year" format="integer" />
<attr name="month" format="integer" />
<attr name="day" format="integer" />
<attr name="hour" format="integer" />
<attr name="minute" format="integer" />
</declare-styleable>
</resources>


次はDateTimePickerのスース [DateTimePicker.java]
やってるのはほぼDatePickerとTimePickerの機能をラッピングするだけ。
それと下段のTimePickerをCheckBoxで表示/非表示させただけ。

/**
* http://babukuma.com
*/
package com.babukuma.android.view;

import java.util.Calendar;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.DatePicker;
import android.widget.LinearLayout;
import android.widget.TimePicker;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.DatePicker.OnDateChangedListener;
import android.widget.TimePicker.OnTimeChangedListener;

import com.babukuma.android.test.R;

/**
* @author babukuma
*/
public class DateTimePicker extends LinearLayout {
/**
* @author babukuma
*/
public interface OnDateTimeChangedListener {
/**
* @param view
* The view associated with this listener.
* @param year
* The year that was set.
* @param monthOfYear
* The month that was set (0-11) for compatibility with
* {@link java.util.Calendar}.
* @param dayOfMonth
* The day of the month that was set.
* @param hourOfDay
* The current hour.
* @param minute
* The current minute.
*/
void onDateTimeChanged(DateTimePicker view, int year, int monthOfYear,
int dayOfMonth, int hourOfDay, int minute);
}

private OnDateTimeChangedListener onDateTimeChangedListener;

private final DatePicker datePicker;
private final CheckBox enableTimeCheckBox;
private final TimePicker timePicker;

/**
* @param context
*/
public DateTimePicker(final Context context) {
this(context, null);
}

/**
* @param context
* @param attrs
*/
public DateTimePicker(final Context context, final AttributeSet attrs) {
super(context, attrs);

// Layout
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.datetime_picker, this, true);

// Attribute
Calendar calendar = Calendar.getInstance();
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.DataTimePicker);
final int _currentYear = a.getInt(R.styleable.DataTimePicker_year,
calendar.get(Calendar.YEAR));
final int _currentMonth = a.getInt(R.styleable.DataTimePicker_month,
calendar.get(Calendar.MONTH));
final int _currentDay = a.getInt(R.styleable.DataTimePicker_day,
calendar.get(Calendar.DAY_OF_MONTH));
final int _currentHour = a.getInt(R.styleable.DataTimePicker_hour,
calendar.get(Calendar.HOUR_OF_DAY));
final int _currentMinute = a.getInt(R.styleable.DataTimePicker_minute,
calendar.get(Calendar.MINUTE));

// DatePicker
datePicker = (DatePicker) findViewById(R.id._babukuma_datetime_picker_date_picker);
datePicker.init(_currentYear, _currentMonth, _currentDay,
new OnDateChangedListener() {

@Override
public void onDateChanged(final DatePicker view,
final int year, final int monthOfYear,
final int dayOfMonth) {
if (onDateTimeChangedListener != null) {
onDateTimeChangedListener.onDateTimeChanged(
DateTimePicker.this, year, monthOfYear,
dayOfMonth, timePicker.getCurrentHour(),
timePicker.getCurrentMinute());
}
}
});

// Enable Time checkbox
enableTimeCheckBox = (CheckBox) findViewById(R.id._babukuma_datetime_picker_enable_time);
enableTimeCheckBox
.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
timePicker.setEnabled(isChecked);
timePicker.setVisibility((enableTimeCheckBox
.isChecked() ? View.VISIBLE : View.INVISIBLE));
}
});

// TimePicker
timePicker = (TimePicker) findViewById(R.id._babukuma_datetime_picker_time_picker);
timePicker.setOnTimeChangedListener(new OnTimeChangedListener() {
@Override
public void onTimeChanged(final TimePicker view,
final int hourOfDay, final int minute) {
if (onDateTimeChangedListener != null) {
onDateTimeChangedListener.onDateTimeChanged(
DateTimePicker.this, datePicker.getYear(),
datePicker.getMonth(), datePicker.getDayOfMonth(),
hourOfDay, minute);
}
}
});
timePicker.setCurrentHour(_currentHour);
timePicker.setCurrentMinute(_currentMinute);
timePicker.setEnabled(enableTimeCheckBox.isChecked());
timePicker.setVisibility((enableTimeCheckBox.isChecked() ? View.VISIBLE
: View.INVISIBLE));
}

public void setOnDateTimeChangedListener(
OnDateTimeChangedListener onDateTimeChangedListener) {
this.onDateTimeChangedListener = onDateTimeChangedListener;
}

public void updateDateTime(int year, int monthOfYear, int dayOfMonth,
int currentHour, int currentMinute) {
datePicker.updateDate(year, monthOfYear, dayOfMonth);
timePicker.setCurrentHour(currentHour);
timePicker.setCurrentMinute(currentMinute);
}

public void updateDate(int year, int monthOfYear, int dayOfMonth) {
datePicker.updateDate(year, monthOfYear, dayOfMonth);
}

public void setIs24HourView(final boolean is24HourView) {
timePicker.setIs24HourView(is24HourView);
}

public int getYear() {
return datePicker.getYear();
}

public int getMonth() {
return datePicker.getMonth();
}

public int getDayOfMonth() {
return datePicker.getDayOfMonth();
}

public int getCurrentHour() {
return timePicker.getCurrentHour();
}

public int getCurrentMinute() {
return timePicker.getCurrentMinute();
}

public boolean enableTime() {
return enableTimeCheckBox.isChecked();
}
}


とりあえずはこれで必要な簡単な機能はできてると思う。
後でもっと完成度を上げよう。

下からは作ったDateTimePickerをテスト


テスト用レイアウト [res/layout/datetime_picker_test.xml]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:orientation="vertical">
<TextView android:id="@+id/datetime_picker_activity_text_view"
android:layout_width="fill_parent" android:layout_height="48dip"
android:textColor="#000000" android:background="#CCCCCC"
android:gravity="center" android:text="time"></TextView>
<com.babukuma.android.view.DateTimePicker
android:layout_width="wrap_content" android:layout_height="wrap_content"
year="2010" month="1" day="29" hour="14" minute="1" startYear="2000"
android:id="@+id/datetime_picker_activity_datetime_picker">
</com.babukuma.android.view.DateTimePicker>
</LinearLayout>


テスト用ソース [DateTimePickerActivity.java]

package com.babukuma.android.test;

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

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

import com.babukuma.android.view.DateTimePicker;
import com.babukuma.android.view.DateTimePicker.OnDateTimeChangedListener;

public class DateTimePickerActivity extends Activity {
final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");

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

final TextView timeView = (TextView) findViewById(R.id.datetime_picker_activity_text_view);
final DateTimePicker dateTimePicker = (DateTimePicker) findViewById(R.id.datetime_picker_activity_datetime_picker);
dateTimePicker
.setOnDateTimeChangedListener(new OnDateTimeChangedListener() {
@Override
public void onDateTimeChanged(DateTimePicker view,
int year, int monthOfYear, int dayOfMonth,
int hourOfDay, int minute) {
Calendar calendar = Calendar.getInstance();
calendar.set(year, monthOfYear, dayOfMonth, hourOfDay,
minute);
timeView.setText(dateFormat.format(calendar.getTime()));
}
});

Calendar calendar = Calendar.getInstance();
calendar.set(dateTimePicker.getYear(), dateTimePicker.getMonth(),
dateTimePicker.getDayOfMonth(),
dateTimePicker.getCurrentHour(), dateTimePicker
.getCurrentMinute());
timeView.setText(dateFormat.format(calendar.getTime()));
}
}


次回はDateTimePickerDialogを作ってみる。