在android中以分钟为间隔显示TimePicker

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20214547/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 02:28:53  来源:igfitidea点击:

Show TimePicker with minutes intervals in android

androidintervalsandroid-timepicker

提问by Sergio76

My application show a TimePickerDialog to set a time. I want that the timePickerDialog show the minutes with an interval of 5 minutes.

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

This works fine with this code:

这适用于以下代码:

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;
    }
}

Although only minutes can be selected with an interval of five minutes, the timepickerdialog looks like:

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

hours and minutes

小时和分钟

do not know how the minutes also show the range of 5 minutes, as in this picture:

不知道分钟怎么也显示5分钟的范围,如下图:

hours and minutes - 5

小时和分钟 - 5

I have searched but can not find the solution.

我已经搜索过但找不到解决方案。

回答by Tanmay Mandal

Use the following the custom class called CustomTimePickerDialog, which I think solve your problem.

使用以下名为 的自定义类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();
        }
    }
}

Here is the demonstrating screenshot.

这是演示屏幕截图。

enter image description here

在此处输入图片说明

回答by Lukas Lechner

There is this awesome library MaterialDateTimePickerthat creates beautiful styled material timepickers.

有这个很棒的库MaterialDateTimePicker可以创建漂亮的样式材料时间选择器。

You can use one of the following methods to define your interval:

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

  • setSelectableTimes(Timepoint[] times) You can pass in an array of Timepoints. These values are the only valid selections in the picker. setMinTime(Timepoint time) and setMaxTime(Timepoint time) will further trim this list down.

  • setTimeInterval(int hourInterval, int minuteInterval, int secondInterval) Set the interval for selectable times in the TimePickerDialog. This is a convenience wrapper around setSelectableTimes

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

  • setTimeInterval(int hourInterval, int minuteInterval, int secondInterval) 在 TimePickerDialog 中设置可选时间的间隔。这是 setSelectableTimes 的便利包装器

回答by Robin

As @anddev84 said, you can do it with your own customized TimePickerDialog.

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

However, take a look of the source code you can find:

但是,看看您可以找到的源代码:

  1. TimePickerDialog is a frame layout, see this file. And it just contains a TimePicker
  2. The TimePicker widget is just a linear layout, see this file. And you can see the minute spinner is a NumberPicker
  3. Refer to the code of NumberPicker, you will find it has a public method setDisplayedValues(String[] displayedValues)

    /**
     * Sets the values to be displayed.
     *
     * @param displayedValues The displayed values.
     */
    public void setDisplayedValues(String[] displayedValues)
    
  1. TimePickerDialog 是一个框架布局,见这个文件。它只包含一个TimePicker
  2. TimePicker 小部件只是一个线性布局,请参阅此文件。你可以看到分钟微调器是一个NumberPicker
  3. 参考NumberPicker的代码,你会发现它有一个公共方法 setDisplayedValues(String[] displayValues)

    /**
     * Sets the values to be displayed.
     *
     * @param displayedValues The displayed values.
     */
    public void setDisplayedValues(String[] displayedValues)
    

So, with these information, I suppose you can simply customize your own time picker dialog with limited minutes displayed.

因此,有了这些信息,我想您可以简单地自定义您自己的时间选择器对话框,并显示有限的分钟数。

回答by Tharik ahamed

/**
 * 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);
    }
}

回答by benkc

I've made an addition to the excellent accepted answer above. The problem with it is that, in at least some versions of Android, when you change the selected time it will replace the dialog title with an incorrect time value. You can't override the offending method, updateTitle(), but you can intercept the call at onTimeChanged() and either not call super or call it with fixed arguments.

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

I keyed mine off of whether the setTitle() method had been called with a non-zero string ID, but you could just have a getter/setter for the boolean itself or whatever.

我不知道是否使用非零字符串 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;

回答by Yevhenii Kanivets

Struggled with 30 min interval more then hour. Might struggle more if wouldn't see the comment of @Lee. So just post a full code of dialog with 30 min interval:

挣扎了 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;
        }
    }

回答by anddev84

Looking at the code for TimePickerDialog, it doesn't appear they give you a way to directly modify the TimePickerbefore it gets shown to the user and you see the "wrong minutes" are you show in the picture. See TimePickerDialog.java

查看 的代码TimePickerDialogTimePicker在它显示给用户之前,它们似乎没有给您直接修改的方法,并且您会看到图片中显示的“错误分钟数”。参见TimePickerDialog.java

My recommendation is to create your own TimePickerDialog, basing the design off the Android one. It might sound daunting at first, but

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

  1. that way you can customize the implementation however you want, including initializing the TimePickervalues to display for the minutes (as mentioned here), and also
  2. it actually shouldn't be very hard, the Android TimePickerDialog.java itself is only 160 lines, very manageable.
  1. 这样无论你想要的,包括初始化,您可以自定义实现TimePicker值显示为分钟(如提到这里),也
  2. 其实应该不难,Android TimePickerDialog.java 本身只有160行,很容易管理。

回答by Adrián Rivero

The answer above works really fine for older version of Android, but it didn't work for me in Android 7 Nougat, basically the date picker is changed completely to use the Clock mode... I kind of merge the code proposed here with https://gist.github.com/jeffdgr8/6bc5f990bf0c13a7334ce385d482af9f, then it set by default the mode of the TimePickerDialog to show the Spinner controls, and it runs the code to show only 15minuts intervals in my case.

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

The code is posted here https://gist.github.com/smaugho/14dae83f3284fa05455ee0a9e4f13099

代码发布在这里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();
    }

}

}

}

回答by gellezzz

If you wont to use the same time picker (not clock) dialog in android 5+ just change the theme. You can change directly in the constructor:

如果您不想在 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;
    }

回答by MJim

Based on Tanmay Mandal's answer shown above, I have implemented a solution for the TimePicker Widget (not the TimePickerDialog). The trick here is to substitute the original TimePicker element in the layout of the activity for a LinearLayout element, in order to add our custom TimePicker programmatically. See example below:

根据上面显示的 Tanmay Mandal 的回答,我已经为 TimePicker 小部件(不是 TimePickerDialog)实现了一个解决方案。这里的技巧是将活动布局中的原始 TimePicker 元素替换为 LinearLayout 元素,以便以编程方式添加我们的自定义 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();
    }

   }

}

And for our activity:

对于我们的活动:

          @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);

}