2010-04-05 37 views
36

Tôi có thể kiểm soát chế độ xem TimePicker của Android để chỉ hiển thị số phút đến khoảng 15 phút không?Android - TimePicker phút tới 15

Có nghĩa là bây giờ là 12:28, hiển thị 12:30 và nhấp vào nút + và - sẽ tăng và giảm 15?

Cảm ơn bạn,

Tee

Trả lời

3

Bạn phải viết TimePicker của riêng bạn. Không chắc chắn nếu bạn có thể mở rộng TimePicker hiện tại và xử lý các sự kiện nút của riêng bạn.

3

Tôi nghĩ rằng tôi đã tìm ra. Có thể là cách ghetto nhưng ...

Đây là những gì tôi đã làm.

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

Làm việc sau cho tôi.

Thứ nhất, trong onCreate:

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

Đặt OnTimeChangedListener:

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

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

Null OnTimeChangedListener (giải thích trong chú thích của updateDisplay dưới đây):

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); 
} 
+0

tôi chỉ tìm thấy một vấn đề với logic của tôi để xác định giá trị phút. Với mã ở trên, nút "+" không hoạt động. Tôi sẽ đăng mã cập nhật khi tôi sửa nó. –

+0

Chúng tôi có thể loại bỏ một số mã xấu xí nếu [lỗi này] (http://code.google.com/p/android/issues/detail?id=27653) đã được sửa. – user250343

1

Trước hết tôi Tôi muốn cảm ơn Andrew vì đã khắc phục lỗi stackoverflow (vòng lặp vô hạn) logic của tôi để tăng thời gian b y 15 phút là một cái gì đó như thế này.Declare int previousMinuteSet = 0 như là một biến thành viên trong lớp đã cho.

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

Hope điều này có thể sẽ rất hữu ích cho mã others.The tôi thay thế trong phương pháp updateDisplay của Andrew, ngoài tất cả những gì là giống nhau.

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

} 

Cập nhật phương pháp hiển thị được sửa đổi cho + và - nút. Phần còn lại của mã là giống như từ Andrew Dyer.

19

Dưới đây là phiên bản của tôi, nơi bạn có thể thiết lập khoảng thời gian:

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

    } 
}; 
+3

nhưng mã này sẽ không đặt giá trị trên và dưới của bộ chọn thời gian cho phù hợp – ANinJa

+1

điều này không hoạt động trên kẹo, bạn có thể đưa ra giải pháp thay thế cho điều này không? –

+0

Ankit Thakkar là đúng. Chính xác hơn, nó đặc biệt là bố cục đồng hồ có vấn đề. Đó là do thực tế phút phút là null. Tôi chưa tìm thấy cách giải quyết vấn đề này. – PAD

18

Tạo một file xml và đặt tên cho nó 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> 

tại tạo lớp hoạt động như thế này

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(); 
      } 
    } 
} 
+0

Giờ không thay đổi khi di chuyển giữa 45 và 00. Tôi chỉ thay đổi sau hai lần lặp lại ... – schabluk

+1

@schabluk bạn đã đúng. Đó là một lỗi. Thực ra tôi đã thêm phút hai lần. Nếu không làm như vậy nó đã không thể tự động cuộn phút. Tôi sẽ cố gắng sửa chữa nó và cập nhật câu trả lời của tôi khi tôi nhận được nó cố định. – Ali

+1

Tôi ước tôi có thể áp dụng giải pháp này nhưng Android Studio khiếu nại 'ClassNotFoundException' trên' Class.forName ("com.android.internal.R $ id") 'ngay cả khi android.jar đã tồn tại trong Thư viện bên ngoài. – CallMeLaNN

2

Tôi đã đưa ra giải pháp dựa trên một số câu trả lời trước cho câu hỏi này và một số câu hỏi của riêng tôi dditions. Giải pháp này đặc biệt ghi đè getCurrentMinute và setCurrentMinute, theo mặc định trả về cho bạn chỉ số phút, không phải giá trị phút (ví dụ: nếu khoảng thời gian của bạn là 15 và bộ chọn có phút hiển thị là 30, nó sẽ trả về 2 mà không có mã này).

Giải pháp này cũng sẽ rollover phút lớn hơn giá trị khoảng thời gian tối đa (một lần nữa nếu khoảng thời gian của bạn là 15, bất kỳ phút nào> 45 sẽ đặt giá trị phút thành 0 và tăng giá trị giờ).

LƯU Ý: Tính năng này được kiểm tra và hoạt động trên Android 4.4 và 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()); 
     } 
    }; 
} 
+0

AttributeSet attrs tham số attrs là gì khi tôi muốn sử dụng mã của bạn? xin vui lòng đề nghị tôi bất kỳ giải pháp Làm thế nào để sử dụng này – Asmi

+0

sử dụng mã của bạn nó chấp nhận 15 phút khác biệt nhưng không hiển thị trên timepicker giá trị 15 phút .. làm thế nào để sử dụng attributeset ở đây .. plz giải thích .. – Asmi

+0

Tôi cần sự giúp đỡ của bạn để sử dụng mã của bạn giúp tôi nếu bạn có thể.. – Asmi

0

Đây là phiên bản tôi đã viết. Đó là mã C# vì tôi đang sử dụng Xamarin, nhưng tôi hy vọng nó sẽ không khó khăn hơn cho bất cứ ai để dịch nó sang Java hơn là với tôi nó là để thực hiện dịch vica versa khi tôi cần phải sao chép một đoạn mã Java.

Có một chút khác biệt so với tiêu chuẩn TimePicker ở chỗ biên giới trên cùng và dưới cùng không liên tục, nhưng đó là một lỗ hổng mà một số người sẽ thấy không đáng kể.

Tôi có thể thực hiện công việc tốt hơn trong việc thiết lập khoảng thời gian tùy chỉnh một cách dễ dàng hơn và không giúp bạn mã hóa các giá trị khoảng thời gian trong quá trình triển khai, nhưng tôi tin rằng bạn có thể đánh bóng giải pháp này nếu bạn muốn rất nhanh!

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

Và đây là những ví dụ về việc sử dụng, một 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> 
Các vấn đề liên quan