在android中显示具有分钟间隔的TimePicker

时间:2013-11-26 10:32:31

标签: android intervals android-timepicker

我的应用程序显示TimePickerDialog来设置时间。 我希望timePickerDialog以5分钟的间隔显示分钟。

这适用于此代码:

private final int TIME_PICKER_INTERVAL=5;
private boolean mIgnoreEvent=false;
…
    public TimePickerDialogs(Context arg0, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView) {
    super(arg0, callBack, hourOfDay, minute, is24HourView);

    formato=Statics.formato;
}

@Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
    //super.onTimeChanged(arg0, arg1, arg2);

    if (mIgnoreEvent)
        return;
    if (minute%TIME_PICKER_INTERVAL!=0){
        int minuteFloor=minute-(minute%TIME_PICKER_INTERVAL);
        minute=minuteFloor + (minute==minuteFloor+1 ? TIME_PICKER_INTERVAL : 0);
        if (minute==60)
            minute=0;
        mIgnoreEvent=true;
        view.setCurrentMinute(minute);
        mIgnoreEvent=false;
    }
}

虽然只能以五分钟的间隔选择分钟,但timepickerdialog看起来像:

hours and minutes

不知道分钟如何显示5分钟的范围,如下图所示:

hours and minutes - 5

我已搜索但无法找到解决方案。

10 个答案:

答案 0 :(得分:117)

使用以下名为CustomTimePickerDialog的自定义类,我认为这样可以解决您的问题。

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import android.app.TimePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.widget.NumberPicker;
import android.widget.TimePicker;

public class CustomTimePickerDialog extends TimePickerDialog {

    private final static int TIME_PICKER_INTERVAL = 5;
    private TimePicker mTimePicker;
    private final OnTimeSetListener mTimeSetListener;

    public CustomTimePickerDialog(Context context, OnTimeSetListener listener,
            int hourOfDay, int minute, boolean is24HourView) {
        super(context, TimePickerDialog.THEME_HOLO_LIGHT, null, hourOfDay,
                minute / TIME_PICKER_INTERVAL, is24HourView);
        mTimeSetListener = listener;
    }

    @Override
    public void updateTime(int hourOfDay, int minuteOfHour) {
        mTimePicker.setCurrentHour(hourOfDay);
        mTimePicker.setCurrentMinute(minuteOfHour / TIME_PICKER_INTERVAL);
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        switch (which) {
            case BUTTON_POSITIVE:
                if (mTimeSetListener != null) {
                    mTimeSetListener.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
                            mTimePicker.getCurrentMinute() * TIME_PICKER_INTERVAL);
                }
                break;
            case BUTTON_NEGATIVE:
                cancel();
                break;
        }
    }

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        try {
            Class<?> classForid = Class.forName("com.android.internal.R$id");
            Field timePickerField = classForid.getField("timePicker");
            mTimePicker = (TimePicker) findViewById(timePickerField.getInt(null));
            Field field = classForid.getField("minute");

            NumberPicker minuteSpinner = (NumberPicker) mTimePicker
                .findViewById(field.getInt(null));
            minuteSpinner.setMinValue(0);
            minuteSpinner.setMaxValue((60 / TIME_PICKER_INTERVAL) - 1);
            List<String> displayedValues = new ArrayList<>();
            for (int i = 0; i < 60; i += TIME_PICKER_INTERVAL) {
                displayedValues.add(String.format("%02d", i));
            }
            minuteSpinner.setDisplayedValues(displayedValues
                    .toArray(new String[displayedValues.size()]));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

以下是演示截图。

enter image description here

答案 1 :(得分:16)

有一个很棒的库MaterialDateTimePicker可以创建漂亮的样式材料时间戳。

您可以使用以下方法之一来定义间隔:

  
      
  • setSelectableTimes(Timepoint []次)您可以传入一个时间点数组。这些值是选择器中唯一有效的选择。   setMinTime(Timepoint time)和setMaxTime(Timepoint time)会更进一步   修剪此列表。

  •   
  • setTimeInterval(int hourInterval,int minuteInterval,int secondInterval)设置可选择的时间间隔   TimePickerDialog。这是一个方便的包装   setSelectableTimes

  •   

答案 2 :(得分:6)

正如@ anddev84所说,您可以使用自己定制的TimePickerDialog来完成。

但是,看看你能找到的源代码:

  1. TimePickerDialog是一种框架布局,请参阅此file。它只包含 TimePicker
  2. TimePicker小部件只是一个线性布局,请参阅此file。您可以看到分钟微调器是 NumberPicker
  3. 请参阅NumberPicker的代码,您会发现它有一个公共方法setDisplayedValues(String [] displayedValues)

    /**
     * Sets the values to be displayed.
     *
     * @param displayedValues The displayed values.
     */
    public void setDisplayedValues(String[] displayedValues)
    
  4. 因此,有了这些信息,我想您可以在显示的有限时间内自定义您自己的时间选择器对话框。

答案 3 :(得分:4)

/**
 * Set TimePicker interval by adding a custom minutes list
 *
 * @param timePicker
 */
private void setTimePickerInterval(TimePicker timePicker) {
    try {

        NumberPicker minutePicker = (NumberPicker) timePicker.findViewById(Resources.getSystem().getIdentifier(
                "minute", "id", "android"));
        minutePicker.setMinValue(0);
        minutePicker.setMaxValue((60 / TIME_PICKER_INTERVAL) - 1);
        List<String> displayedValues = new ArrayList<String>();
        for (int i = 0; i < 60; i += TIME_PICKER_INTERVAL) {
            displayedValues.add(String.format("%02d", i));
        }
        minutePicker.setDisplayedValues(displayedValues.toArray(new String[0]));
    } catch (Exception e) {
        Log.e(TAG, "Exception: " + e);
    }
}

答案 4 :(得分:1)

查看TimePickerDialog的代码,它们似乎没有给你一种方法来直接修改TimePicker,然后才能向用户显示,你看到“错误的分钟”是你显示在图片中。见TimePickerDialog.java

我的建议是创建自己的TimePickerDialog,基于Android设计。起初听起来可能令人生畏,但

  1. 这样您可以根据需要自定义实现,包括初始化显示分钟的TimePicker值(如上所述here),以及
  2. 它实际上应该不是很难,Android TimePickerDialog.java本身只有160行,非常易于管理。

答案 5 :(得分:1)

我已经对上面提到的优秀答案做了补充。它的问题在于,在至少某些Android版本中,当您更改所选时间时,它将使用不正确的时间值替换对话框标题。你不能覆盖有问题的方法updateTitle(),但你可以在onTimeChanged()上拦截调用,不要调用super或用固定参数调用它。

我已经知道是否使用非零字符串ID调用了setTitle()方法,但你可以为布尔本身或其他任何东西设置一个getter / setter。

@Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute)
{
    if (autoTitle)
    {
        // Super will call a private updateTitle() method, so lets make
        // sure it has the right minute value.
        super.onTimeChanged(view, hourOfDay, minute * TIME_PICKER_INTERVAL);
    }
    else
    {
        // do nothing
    }
}

@Override
public void setTitle(int id)
{
    super.setTitle(id);
    autoTitle = (id == 0);
}

...

private boolean autoTitle = true;

答案 6 :(得分:1)

以30分钟的间隔挣扎超过一小时。如果不能看到@Lee的评论,可能会更加挣扎。所以只需发布30分钟间隔的完整对话代码:

public class IntervalTimePickerDialog extends TimePickerDialog {
    private static final String TAG = "IntervalPickerDialog";

    private final static int TIME_PICKER_INTERVAL = 30;
    private TimePicker timePicker;
    private final OnTimeSetListener callback;

    private int lastHour = -1;
    private int lastMinute = -1;

    public IntervalTimePickerDialog(Context context, int themeId, OnTimeSetListener callBack,
                                    int hourOfDay, int minute, boolean is24HourView) {
        super(context, themeId, callBack, hourOfDay, minute / TIME_PICKER_INTERVAL,
                is24HourView);
        lastHour = hourOfDay;
        lastMinute = minute;
        this.callback = callBack;
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        if (callback != null && timePicker != null) {
            timePicker.clearFocus();
            callback.onTimeSet(timePicker, timePicker.getCurrentHour(),
                    timePicker.getCurrentMinute() * TIME_PICKER_INTERVAL);
        }
    }

    @Override
    protected void onStop() {
    }

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        try {
            Class<?> classForid = Class.forName("com.android.internal.R$id");
            Field timePickerField = classForid.getField("timePicker");
            this.timePicker = (TimePicker) findViewById(timePickerField.getInt(null));
            Field field = classForid.getField("minute");

            NumberPicker mMinuteSpinner = (NumberPicker) timePicker.findViewById(field.getInt(null));
            mMinuteSpinner.setMinValue(0);
            mMinuteSpinner.setMaxValue((60 / TIME_PICKER_INTERVAL) - 1);
            List<String> displayedValues = new ArrayList<>();
            for (int i = 0; i < 60; i += TIME_PICKER_INTERVAL) {
                displayedValues.add(String.format("%02d", i));
            }
            mMinuteSpinner.setDisplayedValues(displayedValues.toArray(new String[0]));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
        super.onTimeChanged(view, hourOfDay, minute);
        if (lastHour != hourOfDay && lastMinute != minute) {
            view.setCurrentHour(lastHour);
            lastMinute = minute;
        } else {
            lastHour = hourOfDay;
            lastMinute = minute;
        }
    }

答案 7 :(得分:0)

上面的答案适用于旧版本的Android,但它在Android 7 Nougat中对我不起作用,基本上日期选择器完全改为使用时钟模式...我有点合并建议的代码在这里使用https://gist.github.com/jeffdgr8/6bc5f990bf0c13a7334ce385d482af9f,然后它默认设置TimePickerDialog的模式来显示Spinner控件,它运行代码以在我的情况下仅显示15minuts间隔。

代码发布在https://gist.github.com/smaugho/14dae83f3284fa05455ee0a9e4f13099

public class CustomTimePickerDialog extends TimePickerDialog {

private final static int TIME_PICKER_INTERVAL = 15;
private TimePicker timePicker;
private final OnTimeSetListener callback;

  public HorekoTimePicker(Context context,
        OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView) {
      super(context, callBack, hourOfDay, minute/TIME_PICKER_INTERVAL, is24HourView);
      this.callback = callBack;
    fixSpinner(context, hourOfDay, minute, is24HourView);
  }

/**
 * Workaround for this bug: https://code.google.com/p/android/issues/detail?id=222208
 * In Android 7.0 Nougat, spinner mode for the TimePicker in TimePickerDialog is
 * incorrectly displayed as clock, even when the theme specifies otherwise, such as:
 *
 *  <resources>
 *      <style name="Theme.MyApp" parent="Theme.AppCompat.Light.NoActionBar">
 *          <item name="android:timePickerStyle">@style/Widget.MyApp.TimePicker</item>
 *      </style>
 *
 *      <style name="Widget.MyApp.TimePicker" parent="android:Widget.Material.TimePicker">
 *          <item name="android:timePickerMode">spinner</item>
 *      </style>
 *  </resources>
 *
 * May also pass TimePickerDialog.THEME_HOLO_LIGHT as an argument to the constructor,
 * as this theme has the TimePickerMode set to spinner.
 *
 * Taken from: https://gist.github.com/jeffdgr8/6bc5f990bf0c13a7334ce385d482af9f
 */
private void fixSpinner(Context context, int hourOfDay, int minute, boolean is24HourView) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // android:timePickerMode spinner and clock began in Lollipop
        try {

            // Get the theme's android:timePickerMode
            final int MODE_SPINNER = 1;
            Class<?> styleableClass = Class.forName("com.android.internal.R$styleable");
            Field timePickerStyleableField = styleableClass.getField("TimePicker");
            int[] timePickerStyleable = (int[]) timePickerStyleableField.get(null);
            final TypedArray a = context.obtainStyledAttributes(null, timePickerStyleable, android.R.attr.timePickerStyle, 0);
            Field timePickerModeStyleableField = styleableClass.getField("TimePicker_timePickerMode");
            int timePickerModeStyleable = timePickerModeStyleableField.getInt(null);
            final int mode = a.getInt(timePickerModeStyleable, MODE_SPINNER);
            a.recycle();

            if (mode == MODE_SPINNER) {

                timePicker = (TimePicker) findField(TimePickerDialog.class, TimePicker.class, "mTimePicker").get(this);
                Class<?> delegateClass = Class.forName("android.widget.TimePicker$TimePickerDelegate");
                Field delegateField = findField(TimePicker.class, delegateClass, "mDelegate");
                Object delegate = delegateField.get(timePicker);
                Class<?> spinnerDelegateClass;
                if (Build.VERSION.SDK_INT != Build.VERSION_CODES.LOLLIPOP) {
                    spinnerDelegateClass = Class.forName("android.widget.TimePickerSpinnerDelegate");
                } else {
                    // TimePickerSpinnerDelegate was initially misnamed TimePickerClockDelegate in API 21!
                    spinnerDelegateClass = Class.forName("android.widget.TimePickerClockDelegate");
                }

                // In 7.0 Nougat for some reason the timePickerMode is ignored and the delegate is TimePickerClockDelegate
                if (delegate.getClass() != spinnerDelegateClass) {
                    delegateField.set(timePicker, null); // throw out the TimePickerClockDelegate!
                    timePicker.removeAllViews(); // remove the TimePickerClockDelegate views
                    Constructor spinnerDelegateConstructor = spinnerDelegateClass.getConstructor(TimePicker.class, Context.class, AttributeSet.class, int.class, int.class);
                    spinnerDelegateConstructor.setAccessible(true);
                    // Instantiate a TimePickerSpinnerDelegate
                    delegate = spinnerDelegateConstructor.newInstance(timePicker, context, null, android.R.attr.timePickerStyle, 0);
                    delegateField.set(timePicker, delegate); // set the TimePicker.mDelegate to the spinner delegate
                    // Set up the TimePicker again, with the TimePickerSpinnerDelegate
                    timePicker.setIs24HourView(is24HourView);
                    timePicker.setCurrentHour(hourOfDay);
                    timePicker.setCurrentMinute(minute);
                    timePicker.setOnTimeChangedListener(this);
                }

                setTimeIntervals();
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

private static Field findField(Class objectClass, Class fieldClass, String expectedName) {
    try {
        Field field = objectClass.getDeclaredField(expectedName);
        field.setAccessible(true);
        return field;
    } catch (NoSuchFieldException e) {} // ignore
    // search for it if it wasn't found under the expected ivar name
    for (Field searchField : objectClass.getDeclaredFields()) {
        if (searchField.getType() == fieldClass) {
            searchField.setAccessible(true);
            return searchField;
        }
    }
    return null;
}

  @Override
protected void onStop() { }

/*
 * Feature #363: (Un)availability times in 15min interval
 * https://abix.webhop.net/redmine/issues/363
 * Solution extracted from
 * http://stackoverflow.com/questions/20214547/show-timepicker-with-minutes-intervals-in-android
 */

@Override
public void onClick(DialogInterface dialog, int which) {
    super.onClick(dialog, which);

    if (callback != null && timePicker != null) {
        timePicker.clearFocus();
        callback.onTimeSet(timePicker, timePicker.getCurrentHour(),
            timePicker.getCurrentMinute()*TIME_PICKER_INTERVAL);
    }
}

private void setTimeIntervals() {
    try {
        Class<?> classForid = Class.forName("com.android.internal.R$id");
        Field field = classForid.getField("minute");

        NumberPicker mMinuteSpinner = (NumberPicker) timePicker.findViewById(field.getInt(null));
        mMinuteSpinner.setMinValue(0);
        mMinuteSpinner.setMaxValue((60 / TIME_PICKER_INTERVAL) - 1);
        List<String> displayedValues = new ArrayList<String>();
        for (int i = 0; i < 60; i += TIME_PICKER_INTERVAL) {
            displayedValues.add(String.format("%02d", i));
        }
        mMinuteSpinner.setDisplayedValues(displayedValues.toArray(new String[0]));

    } catch (Exception e) {
        e.printStackTrace();
    }

}

}

答案 8 :(得分:-1)

如果您不想在android 5+中使用相同的时间选择器(不是时钟)对话框,只需更改主题即可。您可以直接在构造函数中进行更改:

 public CustomTimePickerDialog(Context context, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView, int time_interval) {
        super(context, TimePickerDialog.THEME_HOLO_LIGHT, callBack, hourOfDay, minute / time_interval, is24HourView);
        this.TIME_PICKER_INTERVAL = time_interval;
        this.callback = callBack;
    }

答案 9 :(得分:-2)

基于上面显示的Tanmay Mandal的答案,我已经为TimePicker Widget(而不是TimePickerDialog)实现了一个解决方案。这里的技巧是在LinearLayout元素的活动布局中替换原始的TimePicker元素,以便以编程方式添加我们的自定义TimePicker。见下面的例子:

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.widget.NumberPicker;
import android.widget.TimePicker;

public class MyTimePicker extends TimePicker {

  private static final int TIME_PICKER_INTERVAL = 5;

    public MyTimePicker(Context context) {
        super(context);
    }

    @Override
    public Integer getCurrentMinute() {
        return super.getCurrentMinute()*TIME_PICKER_INTERVAL;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        try {
            Class<?> classForid = Class.forName("com.android.internal.R$id");
            Field field = classForid.getField("minute");

            NumberPicker mMinuteSpinner = (NumberPicker) findViewById(field.getInt(null));
            mMinuteSpinner.setMinValue(0);
            mMinuteSpinner.setMaxValue((60 / TIME_PICKER_INTERVAL) - 1);
            List<String> displayedValues = new ArrayList<String>();
            for (int i = 0; i < 60; i += TIME_PICKER_INTERVAL)
                displayedValues.add(String.format("%02d", i));
             mMinuteSpinner.setDisplayedValues(displayedValues.toArray(new String[0]));     
        } catch (Exception e) {
        e.printStackTrace();
    }

   }

}

对于我们的活动:

          @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

            LinearLayout ll = (LinearLayout) findViewById(R.id.myLinearLayout);
            ll.removeAllViews();
            MyTimePicker tp = new MyTimePicker(this);
            tp.setIs24HourView(true);
            Calendar cal = Calendar.getInstance(); // Current time
        tp.setCurrentHour(cal.get(Calendar.HOUR_OF_DAY));
            tp.setCurrentMinute(cal.get(Calendar.MINUTE)/5); // Aprox current minute
            ll.addView(tp);

}