Affichage du chronomètre avec des intervalles de minutes sur android
Ma demande de montrer un TimePickerDialog pour régler l'heure. Je veux que le timePickerDialog montre les minutes avec un intervalle de 5 minutes.
cela fonctionne très bien avec ce 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;
}
}
bien que seules les minutes puissent être sélectionnées avec un intervalle de cinq minutes, le timepickerdialog ressemble à:
Je ne sais pas comment les minutes montrent aussi la gamme de 5 minutes, comme sur cette image:
j'ai cherché mais je ne trouve pas la solution.
10 réponses
utilisez la classe personnalisée suivante appelée CustomTimePickerDialog
, qui je pense résoudre votre problème.
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();
}
}
}
Voici la capture d'écran de démonstration.
Il y a cette incroyable bibliothèque MaterialDateTimePicker qui crée de belles de style matériel timepickers.
Vous pouvez utiliser l'une des méthodes suivantes pour définir votre intervalle:
setSelectableTimes(mesure dans le temps[] temps), Vous pouvez passer un tableau de Points dans le temps. Ces valeurs sont les seules sélections valides dans le sélecteur. setMinTime (Timepoint time) et setMaxTime(Timepoint Time) temps) garniture de cette liste vers le bas.
setTimeInterval (int hourInterval, int minuteInterval, int secondInterval) fixe l'intervalle pour les temps sélectionnables dans le TimePickerDialog. C'est un wrapper autour de commodité setselectable times
comme @anddev84 l'a dit, Vous pouvez le faire avec votre propre TimePickerDialog personnalisé.
cependant, jetez un oeil au code source que vous pouvez trouver:
- TimePickerDialog est une mise en page de cadre, voir ce fichier . Et il contient juste un TimePicker
- le widget TimePicker n'est qu'une mise en page linéaire, voir ce fichier . Et vous pouvez voir la minute spinner est un Numbererpicker
-
Consulter le code de NumberPicker , vous trouverez qu'il a une méthode publique setDisplayedValues(String[] displayedValues)
/** * Sets the values to be displayed. * * @param displayedValues The displayed values. */ public void setDisplayedValues(String[] displayedValues)
donc, avec ces informations, je suppose que vous pouvez simplement personnaliser votre propre dialogue de chronométrage avec des minutes limitées afficher.
/**
* 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);
}
}
en regardant le code pour TimePickerDialog
, il ne semble pas qu'ils vous donnent un moyen de modifier directement le TimePicker
avant qu'il soit montré à l'utilisateur et vous voyez les "mauvaises minutes" Sont vous montrer dans l'image. Voir TimePickerDialog.java
ma recommandation est de créer votre propre TimePickerDialog, en basant le design sur L'Android one. Cela peut sembler intimidant au début, mais
- de cette façon, vous pouvez personnaliser l'implémentation comme vous le souhaitez, y compris initialiser les valeurs
TimePicker
à afficher pour les minutes (comme mentionné ici ), et aussi - ça ne devrait pas être très dur, L'Android TimePickerDialog.java lui-même n'est que de 160 lignes, très maniable.
j'ai ajouté un ajout à l'excellente réponse acceptée ci-dessus. Le problème avec elle est que, dans au moins certaines versions D'Android, lorsque vous changez l'heure sélectionnée, il remplacera le titre de dialogue avec une valeur de temps incorrecte. Vous ne pouvez pas outrepasser la méthode offensante, updateTitle(), mais vous pouvez intercepter l'appel à onTimeChanged() et soit ne pas appeler super ou l'appeler avec des arguments fixes.
j'ai cherché à savoir si la méthode setTitle() avait été appelé avec un ID de chaîne non-zéro, mais vous pourriez juste avoir un getter / setter pour le booléen lui-même ou quoi que ce soit.
@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;
luttait avec un intervalle de plus de 30 min. Pourrait se battre plus si ne verrait pas le commentaire de @Lee. Il suffit donc de poster un code complet de dialogue avec un intervalle de 30 min:
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;
}
}
la réponse ci-dessus fonctionne très bien pour la version plus ancienne D'Android, mais il n'a pas fonctionné pour moi dans Android 7 Nougat, essentiellement la date picker est complètement changé pour utiliser le mode horloge... J'ai en quelque sorte fusionné le code proposé ici avec https://gist.github.com/jeffdgr8/6bc5f990bf0c13a7334ce385d482af9f , puis il a défini par défaut le mode du TimePickerDialog pour afficher les commandes de Spinner, et il exécute le code pour afficher seulement 15minuts intervalles dans mon cas.
le code est affiché ici 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
* /q/show-timepicker-with-minutes-intervals-in-android-50106/"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();
}
}
}
basé sur la réponse de Tanmay Mandal montrée ci-dessus, j'ai implémenté une solution pour le Widget TimePicker (pas le TimePickerDialog). L'astuce ici est de remplacer L'élément original TimePicker dans la mise en page de l'activité par un élément LinearLayout, afin d'ajouter notre programmateur personnalisé. Voir l'exemple ci-dessous:
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();
}
}
}
et pour notre activité:
@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);
}
si vous ne voulez pas utiliser la même boîte de dialogue time picker (not clock) dans android 5+ Il suffit de changer le thème. Vous pouvez changer directement dans le constructeur:
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;
}