LoginSignup
3
5

More than 5 years have passed since last update.

30分単位の時刻を選択するTimePicker

Posted at

こんな感じのダイアログで30分単位の時刻を選択するやつを作ったので書いておく。
time_picker_dialog.png

  • Fragmentから呼び出して使う(DialogFragmentベース)
  • Gingerbread(API Level 10)でも使える
  • 選択した時と分をintで取得
  • 初期値をCalenderか、intの時と分で指定できる
  • v11以上ではNumberPickerを使う
  • v10以下ではSpinnerを使う

使い方

ダイアログを開くときはこんな感じで呼び出す。
初期値はCalendarで渡すか、 set(int hour, int minute)で渡す。

TimePickerFragment picker = TimePickerFragment.newInstance(this);
picker.set(calendar);
picker.show(getFragmentManager(), "time_picker");

選択された値は、呼び出し元FragmentのonTimeSetで受け取る。

HogeFragment
public class HogeFragment extends Fragment implements TimePickerFragment.TimePickerListener {
    @Override
    public void onTimeSet(int hourOfDay, int minute) {
        // 選択された時、分がhourOfDay、minuteに入ってくる
    }
}

本体コード

DialogFragmentの全体はこんな感じ。

TimePickerFragment.java
public class TimePickerFragment extends DialogFragment {

    public interface TimePickerListener {
        void onTimeSet(int hourOfDay, int minute);
    }

    public static TimePickerFragment newInstance(Fragment fragment) {
        TimePickerFragment dialog = new TimePickerFragment();
        dialog.setTargetFragment(fragment, 0);
        return dialog;
    }

    private TimePickerListener getListener() {
        try {
            return (TimePickerListener) getTargetFragment();
        } catch (ClassCastException e) {
            return null;
        }
    }

    private View hour;
    private View minute;

    public void set(int hour, int minute) {
        Bundle args = getArguments();
        if (args == null) {
            args = new Bundle();
        }
        args.putInt("hour", hour);
        args.putInt("minute", minute);
        setArguments(args);
    }

    public void set(Calendar calendar) {
        this.set(calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE));
    }

    private View createPickerView() {
        View view = LayoutInflater.from(getActivity()).inflate(R.layout.time_picker, null);

        int hourValue;
        int minuteValue;
        Bundle args = getArguments();
        if (args != null && args.containsKey("hour")) {
            hourValue = args.getInt("hour");
            minuteValue = args.getInt("minute");
        } else {
            // 初期値が指定されなかった場合は現在時刻
            Calendar now = Calendar.getInstance();
            hourValue = now.get(Calendar.HOUR_OF_DAY);
            minuteValue = now.get(Calendar.MINUTE);
        }
        // 30分刻みに繰り上げる
        if (minuteValue == 0) {
            minuteValue = 0;
        } else if (minuteValue <= 30) {
            minuteValue = 30;
        } else {
            minuteValue = 0;
            hourValue = (hourValue + 1 > 23 ? 0 : hourValue + 1);
        }

        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) {
            NumberPicker hour = (NumberPicker) view.findViewById(R.id.picker_hour);
            hour.setMinValue(0);
            hour.setMaxValue(23);
            hour.setValue(hourValue);
            this.hour = hour;

            NumberPicker minute = (NumberPicker) view.findViewById(R.id.picker_minute);
            minute.setMinValue(0);
            minute.setMaxValue(5);
            minute.setDisplayedValues(new String[]{"00", "30", "00", "30", "00", "30"});
            minute.setValue(minuteValue > 29 ? 1 : 0);
            this.minute = minute;
        } else {
            Spinner hour = (Spinner) view.findViewById(R.id.picker_hour);
            hour.setSelection(hourValue);
            this.hour = hour;

            Spinner minute = (Spinner) view.findViewById(R.id.picker_minute);
            minute.setSelection(minuteValue > 29 ? 1 : 0);
            this.minute = minute;
        }

        return view;
    }

    private int getHour() {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) {
            NumberPicker picker = (NumberPicker) hour;
            return picker.getValue();
        } else {
            Spinner spinner = (Spinner) hour;
            return Integer.parseInt((String) spinner.getSelectedItem());
        }
    }

    private int getMinute() {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) {
            NumberPicker picker = (NumberPicker) minute;
            return (picker.getValue() % 2) == 1 ? 30 : 0;
        } else {
            Spinner spinner = (Spinner) minute;
            return Integer.parseInt((String) spinner.getSelectedItem());
        }
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        super.onCreateDialog(savedInstanceState);

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setView(createPickerView());
        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                TimePickerListener listener = getListener();
                if (listener != null) {
                    listener.onTimeSet(getHour(), getMinute());
                }
            }
        });
        builder.setNegativeButton(android.R.string.cancel, null);
        builder.setCancelable(true);
        return builder.create();
    }
}

ポイントとしては、"00"と"30"の2値だけだと、クルクル~ってスクロールしないので、00と30を数回繰り返した値にしてる。

minute.setDisplayedValues(new String[]{"00", "30", "00", "30", "00", "30"});

Layoutファイルはv11以上向けのNumberPicker版とv10以下向けのSpinner版を用意

layout-v11/time_picker.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center">
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:orientation="horizontal">
        <NumberPicker
            android:id="@+id/picker_hour"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:text=":"
            android:textSize="24sp" />
        <NumberPicker
            android:id="@+id/picker_minute"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</FrameLayout>
layout/time_picker.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center">
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:orientation="horizontal"
        android:padding="16dp">
        <Spinner
            android:id="@+id/picker_hour"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:entries="@array/picker_item_hour"
            android:gravity="center_vertical|right" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:gravity="center"
            android:text=":"
            android:textColor="#ffffff"
            android:textSize="24sp" />
        <Spinner
            android:id="@+id/picker_minute"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:entries="@array/picker_item_minute"
            android:gravity="center_vertical|left" />
    </LinearLayout>
</FrameLayout>
values/picker_item.xml
<resources>
    <string-array name="picker_item_hour">
        <item>0</item>
        <item>1</item>
        <item>2</item>
        <item>3</item>
        <item>4</item>
        <item>5</item>
        <item>6</item>
        <item>7</item>
        <item>8</item>
        <item>9</item>
        <item>10</item>
        <item>11</item>
        <item>12</item>
        <item>13</item>
        <item>14</item>
        <item>15</item>
        <item>16</item>
        <item>17</item>
        <item>18</item>
        <item>19</item>
        <item>20</item>
        <item>21</item>
        <item>22</item>
        <item>23</item>
    </string-array>
    <string-array name="picker_item_minute">
        <item>00</item>
        <item>30</item>
    </string-array>
</resources>
3
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5