【问题标题】:How to set a custom minutes interval in TimePickerDialog in Android如何在 Android 的 TimePickerDialog 中设置自定义分钟间隔
【发布时间】:2011-12-04 12:57:32
【问题描述】:

我有一个 TimePickerDialog 用于设置时间,该时间设置为 TextView 以便显示它。现在,我需要帮助将 TimePicker(在 TimePickerDialog 内)分钟间隔设置为 15 分钟。我看到有一篇与 TimePicker 相关的 15 分钟间隔问题的帖子,但我不知道如何将其应用于 TimePickerDialog,因为我不知道如何使用它在 TimePickerDialog 中创建的 TimePicker。我是 Android 新手,完全迷失在这件事上。提前致谢。

【问题讨论】:

    标签: java android intervals timepicker


    【解决方案1】:

    您可以使用常规 AlertDialog 并使用 setView 来包含自定义 TimePicker 视图。

    【讨论】:

    • 我最终在活动中使用了时间选择器,根本没有对话。它更容易战斗。不管怎么说,还是要谢谢你。如果有人感兴趣,我从这篇文章中获取信息:stackoverflow.com/questions/2580216/…
    【解决方案2】:

    如果您使用时间选择器而不是时间选择器对话框,那很好。但实际上有一个解决方案..这是我用来满足相同要求的..我使用了CustomTimePickerDialog。一切都是一样的,只是代码中的 TimePickerDialog 会变成 CustomTimePickerDialog。

    CustomTimePickerDialog timePickerDialog = new CustomTimePickerDialog(myActivity.this, timeSetListener, 
                Calendar.getInstance().get(Calendar.HOUR), 
                CustomTimePickerDialog.getRoundedMinute(Calendar.getInstance().get(Calendar.MINUTE) + CustomTimePickerDialog.TIME_PICKER_INTERVAL), 
                false
    );
    timePickerDialog.setTitle("2. Select Time");
    timePickerDialog.show();
    

    这是我的 CustomTimePickerDialog 类...只需在您的项目中使用这个类并将 TimePickerDialog 更改为 CustomTimePickerDialog..

    public class CustomTimePickerDialog extends TimePickerDialog{
    
        public static final int TIME_PICKER_INTERVAL=10;
        private boolean mIgnoreEvent=false;
    
        public CustomTimePickerDialog(Context context, OnTimeSetListener callBack, int hourOfDay, int minute,
            boolean is24HourView) {
        super(context, callBack, hourOfDay, minute, is24HourView);
        }
    /*
     * (non-Javadoc)
     * @see android.app.TimePickerDialog#onTimeChanged(android.widget.TimePicker, int, int)
     * Implements Time Change Interval
     */
        @Override
        public void onTimeChanged(TimePicker timePicker, int hourOfDay, int minute) {
            super.onTimeChanged(timePicker, hourOfDay, minute);
            this.setTitle("2. Select Time");
            if (!mIgnoreEvent){
                minute = getRoundedMinute(minute);
                mIgnoreEvent=true;
                timePicker.setCurrentMinute(minute);
                mIgnoreEvent=false;
            }
        }
    
        public static int getRoundedMinute(int minute){
             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;
             }
    
            return minute;
        }
    }
    

    使用此 CustomTimePickerDialog 类后,您需要做的就是在代码中使用 CustomTimePickerDialog 而不是 TimePickerDialog 来访问/覆盖 TimePickerDialog 类的默认函数。简单来说,我的意思是你的 timeSetListener 将在此之后如下......

    private CustomTimePickerDialog.OnTimeSetListener timeSetListener = new CustomTimePickerDialog.OnTimeSetListener() {
        @Override
        public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
    
        }
    }// using CustomTimePickerDialog
    

    【讨论】:

    • 谢谢@Rizwan。该解决方案有效,例如,成功地将可选时间限制为 15 分钟增量。但是,显示在当前分钟值上方和下方的相邻分钟值仍以 1 分钟为增量,而不是 15 分钟为增量。例如,选定的分钟值 30 一侧为 29,另一侧为 31,而不是一侧为 15,另一侧为 45。这会导致有些分散的用户体验。如果相邻值也以 15 分钟为增量,解决方案会更好。您对此有解决方案吗?
    • 谢谢,@Rizwan Sohaib。请参阅上面评论中的问题。
    【解决方案3】:

    结合使用来自@Rizwan 的thisthis 其他线程,我想出了一个组合解决方案,它允许TimePickerDialog 中的任意分钟增量。主要问题是大部分功能都被 android TimePickerDialogTimePicker 类隐藏,而且似乎不允许

    1. 扩展 TimePickerDialog 让我们更容易访问
    2. 使用反射到达显示器内部并访​​问所需的位(见下文)
    3. 重新连接分钟“NumberPicker”以显示我们的价值观
    4. 重新连接 TimePicker 以接收和返回来自 NumberPicker 的值,以尊重我们的自定义增量。
    5. 阻止 onStop() 使其不会在关闭时重置值。

    警告

    到达 UI 内部的主要问题是元素被可能更改的 id 引用,甚至 id 的名称也不能保证永远相同。话虽如此,这是一个有效的、稳定的解决方案,并且可能在可预见的未来有效。在我看来,空的 catch 块应该警告 UI 已经改变并且应该回退到默认的(增加 1 分钟)行为。

    解决方案

        private class DurationTimePickDialog extends TimePickerDialog
        {
            final OnTimeSetListener mCallback;
            TimePicker mTimePicker;
            final int increment;
    
            public DurationTimePickDialog(Context context, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView, int increment)
            {
                super(context, callBack, hourOfDay, minute/increment, is24HourView);
                this.mCallback = callBack;
                this.increment = increment;
            }
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
                    if (mCallback != null && mTimePicker!=null) {
                        mTimePicker.clearFocus();
                        mCallback.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
                                mTimePicker.getCurrentMinute()*increment);
                    }
            }
    
            @Override
            protected void onStop()
            {
                // override and do nothing
            }
    
            @Override
            protected void onCreate(Bundle savedInstanceState)
            {
                super.onCreate(savedInstanceState);
                try
                {
                    Class<?> rClass = Class.forName("com.android.internal.R$id");
                    Field timePicker = rClass.getField("timePicker");
                    this.mTimePicker = (TimePicker)findViewById(timePicker.getInt(null));
                    Field m = rClass.getField("minute");
                    
                    NumberPicker mMinuteSpinner = (NumberPicker)mTimePicker.findViewById(m.getInt(null));
                    mMinuteSpinner.setMinValue(0);
                    mMinuteSpinner.setMaxValue((60/increment)-1);
                    List<String> displayedValues = new ArrayList<String>();
                    for(int i=0;i<60;i+=increment)
                    {
                        displayedValues.add(String.format("%02d", i));
                    }
                    mMinuteSpinner.setDisplayedValues(displayedValues.toArray(new String[0]));
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        }
    
    }
    

    constructor 接受增量值并保留一些其他引用。请注意,这省略了错误检查,我们更喜欢60%increment==0

    onCreate 使用 UI 字段的名称和反射来发现当前位置。同样,这省略了错误检查,并且应该是“故障安全”的,即如果出现问题,则恢复为默认行为。

    onClick 被覆盖以将正确的分钟值返回给回调监听器

    onStop 被覆盖以防止在对话框关闭时再次返回(不正确的)索引值。来吧,你自己试试吧。

    其中大部分来自对 TimePickerDialog 源的挖掘。

    Android 11+ 更新

    上面示例中使用的反射被标记为 greylist-max-q,这意味着在 Android 10 (API 29 - Q) 之后将不再可能。在短期内(直到August 2021),可以将目标版本放回 API 29,同时仍针对 Android 11(API 30 - R)进行构建,但在此日期之后,Play 商店将不再接受这些构建,并且需要API 30 作为构建目标。上述警告中已经预料到并指出了这种最终失败。

    【讨论】:

    • 此解决方案有效,但是当我们更改分钟时,小时数会发生变化。目前我有相同的代码。增量为 30 分钟。当原来的时间是 20:30,我们在分钟滚动到 00 时,它会变成 21:00。如果原始时间是 15:00,我们滚动到分钟到 30,它将返回 14:00。不知道有没有人有同样的问题。。
    • 当我将间隔更改为 15 分钟时,它工作正常。不确定是否有其他类似的解决方案
    • 好的,我设法通过添加最后保存小时和分钟的 onTimeChanged 检查来解决 30 分钟的间隔。如果两者不同,它只会更改分钟而不是使用view.setCurrentHour(lastSavedHour)。但我不确定这是否是一种好方法......但如果有更好的解决方案,请随时告诉我:)
    • 这在 android 5 中似乎不起作用: Field m = rClass.getField("minute"); NumberPicker mMinuteSpinner = (NumberPicker)mTimePicker.findViewById(m.getInt(null));没有找到视图
    【解决方案4】:
    /**
     * Set TimePicker interval by adding a custom minutes list
     * TIME_PICKER_INTERVAL = Enter your Minutes;
     * @param timePicker
     */
    private void setTimePickerInterval(TimePicker timePicker) {
        try {
            int TIME_PICKER_INTERVAL = 10;
            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);
        }
    }
    

    【讨论】:

    • 您的答案设置了间隔,但是在 setOnTimeChangedListener 内部,当我滚动分钟时,它仍然给我增加了 1 分钟。对此有何建议?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多