Подтвердить что ты не робот

Android - TimePicker минут до 15

Могу ли я управлять представлением Android TimePicker, чтобы показывать минуты до 15 минут?

Значение, если оно сейчас 12:28, покажите 12:30, и нажатие кнопки + и - увеличится и уменьшится на 15?

Спасибо,

Тройник

4b9b3361

Ответ 1

Здесь моя версия, где вы можете установить интервал:

private static final int TIME_PICKER_INTERVAL=15;
private boolean mIgnoreEvent=false;

private TimePicker.OnTimeChangedListener mTimePickerListener=new TimePicker.OnTimeChangedListener(){
    public void onTimeChanged(TimePicker timePicker, int hourOfDay, int minute){
        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;
            timePicker.setCurrentMinute(minute);
            mIgnoreEvent=false;
        }

    }
};

Ответ 2

Создайте xml файл и назовите его activity_time_picker.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

 <TimePicker
        android:id="@+id/timePicker1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/layoutHourMinute"
        android:layout_centerInParent="true"

        />

</RelativeLayout>

теперь создайте класс активности, подобный этому

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

import android.annotation.SuppressLint;

import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.NumberPicker;
import android.widget.TimePicker;

public class TimePickerActivity extends Activity {


    TimePicker timePicker;
    private int TIME_PICKER_INTERVAL = 15;
     NumberPicker minutePicker;
     List<String> displayedValues;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
                 super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        setContentView(R.layout.activity_time_picker);
        super.onCreate(savedInstanceState);
        timePicker = (TimePicker)findViewById(R.id.timePicker1);

        timePicker.setIs24HourView(true);
        timePicker.setCurrentHour(0);
        timePicker.setCurrentMinute(0);

        setTimePickerInterval(timePicker);
    }
@SuppressLint("NewApi")
    private void setTimePickerInterval(TimePicker timePicker) {
         try {
                Class<?> classForid = Class.forName("com.android.internal.R$id");
               // Field timePickerField = classForid.getField("timePicker");  

                Field field = classForid.getField("minute");
                minutePicker = (NumberPicker) timePicker
                        .findViewById(field.getInt(null));

                minutePicker.setMinValue(0);
                minutePicker.setMaxValue(3);
                displayedValues = new ArrayList<String>();
                for (int i = 0; i < 60; i += TIME_PICKER_INTERVAL) {
                    displayedValues.add(String.format("%02d", i));
                }
              //  for (int i = 0; i < 60; i += TIME_PICKER_INTERVAL) {
              //      displayedValues.add(String.format("%02d", i));
              //  }
                minutePicker.setDisplayedValues(displayedValues
                        .toArray(new String[0]));
               minutePicker.setWrapSelectorWheel(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
    }
}

Ответ 3

Следующие работали для меня.

Во-первых, in onCreate:

pickStartTime = (TimePicker)findViewById(R.id.StartTime);
pickStartTime.setOnTimeChangedListener(mStartTimeChangedListener);

Установите OnTimeChangedListener:

private TimePicker.OnTimeChangedListener mStartTimeChangedListener =
    new TimePicker.OnTimeChangedListener() {

    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
        updateDisplay(view, startDate, hourOfDay, minute);          
    }
};

Null OnTimeChangedListener (поясняется в комментариях в updateDisplay ниже):

private TimePicker.OnTimeChangedListener mNullTimeChangedListener =
    new TimePicker.OnTimeChangedListener() {

    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {

    }
};

private void updateDisplay(TimePicker timePicker, Date date, int hourOfDay, int minute) { 

    // do calculation of next time 
    int nextMinute = 0;     
    if (minute >= 45 && minute <= 59)
        nextMinute = 45;
    else if(minute >= 30)
        nextMinute = 30;
    else if(minute >= 15)
        nextMinute = 15;
    else if(minute > 0)
        nextMinute = 0;
    else {          
        nextMinute = 45;
    }

    // remove ontimechangedlistener to prevent stackoverflow/infinite loop
    timePicker.setOnTimeChangedListener(mNullTimeChangedListener);

    // set minute
    timePicker.setCurrentMinute(nextMinute);

    // hook up ontimechangedlistener again
    timePicker.setOnTimeChangedListener(mStartTimeChangedListener);

    // update the date variable for use elsewhere in code
    date.setMinutes(nextMinute);  
}

Ответ 4

Вы должны написать свой собственный TimePicker. Не уверен, что вы можете расширить существующий TimePicker и самостоятельно обрабатывать события кнопок.

Ответ 5

private void updateDisplay(TimePicker timePicker, int hourOfDay, int minute) {
    int nextMinute = 0;

    timePicker.setOnTimeChangedListener(mNullTimeChangedListener);

    if (minute >= 45 && minute <= 59) 
        nextMinute = 45;  
    else if (minute  >= 30) 
        nextMinute = 30;
    else if (minute >= 15) 
        nextMinute = 15;
    else if (minute > 0) 
        nextMinute = 0; 
    else { 
        nextMinute = 45; 
    }

    if (minute - nextMinute == 1) {
        if (minute >= 45 && minute <= 59) 
            nextMinute = 00; 
        else if(minute  >= 30) 
            nextMinute = 45;
        else if(minute >= 15) 
            nextMinute = 30;
        else if(minute > 0) 
            nextMinute = 15; 
        else { 
            nextMinute = 15; 
        }
    }

    timePicker.setCurrentMinute(nextMinute);

    timePicker.setOnTimeChangedListener(timePickerChangedListener);

}

Обновить метод отображения, измененный для кнопок + и -. Остальная часть кода такая же, как у Andrew Dyer.

Ответ 6

Думаю, я понял это. Возможно, это гетто, но...

Вот что я сделал.

start_time.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {

            public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
                updateDisplay(hourOfDay, minute);
            }
        });

private void updateDisplay(int hourOfDay, int minute) {
                // do calculation of next time
                // nextTime = calculation of next time;

                // the processed boolean is to prevent infinite loop
        if (!processed) {
            start_time.setCurrentMinute(nextTime);  
                        processed = true;
        } else {
                        processed = false;
                }
    }

Ответ 7

Я придумал решение, основанное на некоторых предыдущих ответах на этот вопрос, и некоторые из моих собственных дополнений. Это решение заметно переопределяет getCurrentMinute и setCurrentMinute, которые по умолчанию возвращают вам минутный индекс, а не минутное значение (т.е. Если ваш минутный интервал равен 15, а сборщик отображает минутку 30, он будет возвращать 2 без этого кода).

В этом решении также будут минуты опрокидывания, превышающие максимальное значение интервала (опять же, если ваш интервал равен 15, любые минуты > 45 устанавливают минутное значение в 0 и увеличивают значение часа).

ПРИМЕЧАНИЕ. Это протестировано и работает на Android 4.4 и 5.0.

public class CustomIntervalTimePicker extends TimePicker {

    private static final int TIME_PICKER_MINUTE_INTERVAL = 15;
    private OnTimeChangedListener timeChangedListener;

    public CustomIntervalTimePicker(Context context, AttributeSet attrs) {
        super(context, attrs);

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

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

    private int maxMinuteIndex() {
        return (60 / TIME_PICKER_MINUTE_INTERVAL) - 1;
    }

    @Override
    public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
        super.setOnTimeChangedListener(internalTimeChangedListener);
        this.timeChangedListener = onTimeChangedListener;
    }

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

    @Override
    public void setCurrentMinute(Integer currentMinute) {
        int cleanMinute = currentMinute / TIME_PICKER_MINUTE_INTERVAL;
        if(currentMinute % TIME_PICKER_MINUTE_INTERVAL > 0) {
            if(cleanMinute == maxMinuteIndex()) {
                cleanMinute = 0;
                setCurrentHour(getCurrentHour()+1);
            } else {
                cleanMinute++;
            }
        }
        super.setCurrentMinute(cleanMinute);
    }

    // We want to proxy all the calls to our member variable OnTimeChangedListener with our own
    // internal listener in order to make sure our overridden getCurrentMinute is called. Without
    // this some versions of android return the underlying minute index.
    private OnTimeChangedListener internalTimeChangedListener = new OnTimeChangedListener() {
        @Override
        public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
            timeChangedListener.onTimeChanged(view, getCurrentHour(), getCurrentMinute());
        }
    };
}

Ответ 8

Прежде всего, я хотел бы поблагодарить Эндрю за то, что он преодолел ошибку stackoverflow (бесконечный цикл). Моя логика для увеличения времени на 15 минут - это что-то вроде этого. Declare int previousMinuteSet = 0 как переменная-член в данном классе.

// remove ontimechangedlistener to prevent stackoverflow/infinite loop timePicker.setOnTimeChangedListener(mNullTimeChangedListener);

        if((minute - previousMinuteSet  == 1) || (minute - previousMinuteSet  == 15) || (minute - previousMinuteSet  == -45)) {
            // set hour
            timePicker.setCurrentHour((hourOfDay + minute / 45) % 12);
            // set minute
            timePicker.setCurrentMinute((minute + 14) % 60);
        } else {
            // set hour
            timePicker.setCurrentHour(hourOfDay);
            // set minute
            timePicker.setCurrentMinute(minute);

        }
        previousMinuteSet = minute;
        // hook up ontimechangedlistener again
        timePicker.setOnTimeChangedListener(timePickerChangedListener);

код >

Надеюсь, что это может быть полезно для других. Код, который я заменил в методе updateDisplay от Andrew, кроме того, что все было таким же.

Ответ 9

Вот версия, которую я написал. Это код С#, потому что я использую Xamarin, но я надеюсь, что кому-то будет труднее перевести его на Java, чем для меня, чтобы выполнить перевод vica versa, когда мне нужно скопировать кусок кода Java.

Это немного отличается от стандартного TimePicker тем, что верхняя и нижняя границы не являются непрерывными, но это недостаток, который некоторые люди найдут несущественными.

Я мог бы лучше справиться с упрощением настройки интервала пользовательских минут и не заставлять вас жестко кодировать значения интервалов в реализации, но я считаю, что вы можете отполировать это решение, если хотите очень быстро!

HourPickerMapper.cs

public class HourPickerMapper
{
    public HourPickerMapper() { }

    public int MapValue(int hour)
    {
        return hour;
    }

    public int MapNumber(int number)
    {
        return number;
    }

    public void InitNumberPicker(NumberPicker numberPicker)
    {
        int[] numbers = new int[24];
        for (var i = 0; i < numbers.Length; i++)
        {
            numbers[i] = i;
        }
        var displayed = numbers.Select(_ => $"{_:00}").ToArray();

        numberPicker.SetDisplayedValues(displayed);
        numberPicker.MinValue = 0;
        numberPicker.MaxValue = displayed.Length - 1;
    }
}

MinutePickerMapper.cs

public class MinutePickerMapper
{
    public MinutePickerMapper() { }

    public int MapValue(int value)
    {
        return (int)Math.Floor(value / 10.0);
    }

    public int MapNumber(int number)
    {
        return number * 10;
    }

    public void InitNumberPicker(NumberPicker numberPicker)
    {
        int[] numbers = new int[6];
        for (var i = 0; i < numbers.Length; i++)
        {
            numbers[i] = i * 10;
        }
        var displayed = numbers.Select(_ => _.ToString()).ToArray();

        numberPicker.SetDisplayedValues(displayed);
        numberPicker.MinValue = 0;
        numberPicker.MaxValue = displayed.Length - 1;
    }
}

И вот пример использования, DialogFragment

public class CustomDateTimePickerDialogFragment : Android.Support.V4.App.DialogFragment
{
    private DateTime _dt;
    private NumberPicker _datePicker, _hourPicker, _minutePicker;
    private DatePickerMapper _datePickerMapper;
    private HourPickerMapper _hourPickerMapper;
    private MinutePickerMapper _minutePickerMapper;

    public event EventHandler<DateTimeSetEventArgs> DateTimeSetEvent;
    public CustomDateTimePickerDialogFragment()
    {
        _dt = DateTime.Now + new TimeSpan(24, 0, 0); // now + 1 day
    }

    public CustomDateTimePickerDialogFragment(DateTime dt)
    {
        _dt = dt;
        if (dt == null)
        {
            _dt = DateTime.Now + new TimeSpan(24, 0, 0); // now + 1 day
        }
    }

    public override Dialog OnCreateDialog(Bundle savedInstanceState)
    {
        AlertDialog.Builder builder = new AlertDialog.Builder(Context);
        builder.SetNeutralButton(Resource.String.dialog_datetime_now, (sender, e) => 
        {
            var eventArgs = new DateTimeSetEventArgs();
            DateTimeSetEvent.Invoke(this, eventArgs);
        });
        builder.SetPositiveButton(Resource.String.dialog_ok, (sender, e) =>
        {
            var hour = _hourPickerMapper.MapNumber(_hourPicker.Value);
            var minute = _minutePickerMapper.MapNumber(_minutePicker.Value);
            var date = _datePickerMapper.MapNumber(_datePicker.Value);
            var eventArgs = new DateTimeSetEventArgs(new DateTime(date.Year, date.Month, date.Day, hour, minute, 0));
            DateTimeSetEvent.Invoke(this, eventArgs);
            Dismiss();
        });
        var dialog = builder.Create();
        dialog.SetView(createDateTimeView(dialog.LayoutInflater));

        _datePicker.Value = _datePickerMapper.MapValue(_dt);
        _hourPicker.Value = _hourPickerMapper.MapValue(_dt.Hour);
        _minutePicker.Value = _minutePickerMapper.MapValue(_dt.Minute);

        return dialog;
    }

    private View createDateTimeView(LayoutInflater inflater)
    {
        View view = inflater.Inflate(Resource.Layout.dialog_custom_datetime_picker, null);

        _datePicker = view.FindViewById<NumberPicker>(Resource.Id.datePicker);
        _datePickerMapper = new DatePickerMapper(DateTime.Now, 10);
        _datePickerMapper.InitNumberPicker(_datePicker);

        var now = DateTime.Now;
        _datePicker.Value = _datePickerMapper.MapValue(now);

        _minutePicker = view.FindViewById<NumberPicker>(Resource.Id.minutePicker);
        _minutePickerMapper = new MinutePickerMapper();
        _minutePickerMapper.InitNumberPicker(_minutePicker);
        _minutePicker.Value = _minutePickerMapper.MapValue(now.Minute);

        _hourPicker = view.FindViewById<NumberPicker>(Resource.Id.hourPicker);
        _hourPickerMapper = new HourPickerMapper();
        _hourPickerMapper.InitNumberPicker(_hourPicker);
        _hourPicker.Value = _hourPickerMapper.MapValue(now.Hour);

        return view;
    }

    public class DateTimeSetEventArgs : EventArgs
    {
        public DateTimeSetEventArgs(DateTime dt)
        {
            IsNow = false;
            DT = dt;
        }

        public DateTimeSetEventArgs()
        {
            IsNow = true;
        }

        public DateTime DT { get; }
        public bool IsNow { get; }
    }
}

dialog_custom_datetime_picker.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="@dimen/dialog_padding"
    >
  <!-- Layout for the DatePicker -->
  <LinearLayout
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
  >
     <LinearLayout
      android:orientation="horizontal"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:gravity="center_vertical"
      >
      <NumberPicker
        android:id="@+id/datePicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:descendantFocusability="blocksDescendants"
        />
      <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=" "
        />
      <NumberPicker
        android:id="@+id/hourPicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:descendantFocusability="blocksDescendants"
        />
         <TextView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text=":"
          />
      <NumberPicker
        android:id="@+id/minutePicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:descendantFocusability="blocksDescendants"
        />       
    </LinearLayout>  
  </LinearLayout>
</LinearLayout>