I\'m having some issues implementing a TimePicker in my application that allows the user to change the time of a database record prior to inserting it.
The problem is th
I've also faced the same problem using API 21, and the problem hasn't been solved yet.
I replaced the TimePicker view for a TimePickerDialog and it worked.
The following code sets a TextView with the time picked from the TimePickerDialog. You can replace the tv.setText() with any logic :
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv = (TextView)findViewById(R.id.textView);
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
TimePickerDialog timePickerDialog = new TimePickerDialog(this,
new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
tv.setText(String.format(Locale.getDefault(),"Hour: %d, Minute: %d ",hourOfDay,minute));
}
}, hour, minute, true);
timePickerDialog.show();
}
I have tested the code. Yes, you are right, TimePicker AM/PM button not invoking onTimeChanged method which it should.
Actually, Its a bug. It has been reported to google. You can find it here
http://code.google.com/p/android/issues/detail?id=18982
Please vote, comment & Star the bug report to raise its priority and to get it fixed by development team as soon as possible.
Velval solution is the only solution that works and compatiple with different Android vesrions. I tried it on api 17 and 23. but it has an issue that it prevent original on click listener on Android 6. so here is what worked with me. to use touch instead of click:
public class MyTimePicker extends TimePicker {
private OnTimeChangedListener onTimeChangedListener;
public MyTimePicker(Context context) {
super(context);
// init();
}
public MyTimePicker(Context context, AttributeSet attrs) {
super(context, attrs);
//init();
}
public MyTimePicker(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MyTimePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Stop ScrollView from getting involved once you interact with the View
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
ViewParent p = getParent();
if (p != null)
p.requestDisallowInterceptTouchEvent(true);
}
return false;
}
@Override
public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
super.setOnTimeChangedListener(onTimeChangedListener);
this.onTimeChangedListener = onTimeChangedListener;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
init();
}
private void init() {
try {
ViewGroup amPmView;
ViewGroup v1 = (ViewGroup) getChildAt(0);
ViewGroup v2 = (ViewGroup) v1.getChildAt(0);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
ViewGroup v3 = (ViewGroup) v2.getChildAt(0);
amPmView = (ViewGroup) v3.getChildAt(3);
} else {
amPmView = (ViewGroup) v2.getChildAt(3);
}
View.OnTouchListener listener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
onTimeChangedListener.onTimeChanged(MyTimePicker.this, getCurrentHour(), getCurrentMinute());
} else {
int hour = getCurrentHour();
if (hour >= 12) {
hour -= 12;
} else {
hour += 12;
}
onTimeChangedListener.onTimeChanged(MyTimePicker.this, hour, getCurrentMinute());
}
return false;
}
};
View am = amPmView.getChildAt(0);
View pm = amPmView.getChildAt(1);
am.setOnTouchListener(listener);
pm.setOnTouchListener(listener);
} catch (Exception e) {
// DO nothing... just ignore the workaround if this fails.
}
}
}
I found this answer, but it didn't work for me, so I thought I would update.
In 3.2 (and above?), the time picker does not have a button for am/pm. Instead it has a NumberPicker. The following code worked for me. The last bit is there because I needed to limit the time selected to no earlier than the 'min' date and no greater than the 'max' date, so I had to check the date selected in the matching DatePicker control:
NumberPicker amPmView = (NumberPicker)((ViewGroup)tp.getChildAt(0)).getChildAt(3);
amPmView.setOnValueChangedListener(new OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker arg0, int arg1, int arg2) {
if(arg0.getValue()== 1){
if (tp.getCurrentHour() < 12)
tp.setCurrentHour(tp.getCurrentHour() + 12);
}
else{
if (tp.getCurrentHour() >= 12)
tp.setCurrentHour(tp.getCurrentHour() - 12);
}
int year = dp.getYear();
int month = dp.getMonth();
int dayOfMonth = dp.getDayOfMonth();
int hourOfDay = tp.getCurrentHour();
int minute = tp.getCurrentMinute();
if (year == min.get(Calendar.YEAR) && month == min.get(Calendar.MONTH) && dayOfMonth == min.get(Calendar.DAY_OF_MONTH)){
if ((hourOfDay < min.get(Calendar.HOUR_OF_DAY))||
(hourOfDay == min.get(Calendar.HOUR_OF_DAY) && (minute < min.get(Calendar.MINUTE)))){
tp.setCurrentHour(min.get(Calendar.HOUR_OF_DAY));
tp.setCurrentMinute(min.get(Calendar.MINUTE));
}
}else if (year == max.get(Calendar.YEAR) && month == max.get(Calendar.MONTH) && dayOfMonth == max.get(Calendar.DAY_OF_MONTH)){
if ((hourOfDay > max.get(Calendar.HOUR_OF_DAY))||
(hourOfDay == max.get(Calendar.HOUR_OF_DAY) && (minute > max.get(Calendar.MINUTE)))){
tp.setCurrentHour(max.get(Calendar.HOUR_OF_DAY));
tp.setCurrentMinute(max.get(Calendar.MINUTE));
}
}
}
});
Please use the below code it is working fine for me.
final TimePicker tp=(TimePicker)findViewById(R.id.timePicker1);
View amPmView = ((ViewGroup)tp.getChildAt(0)).getChildAt(2);
if(amPmView instanceof Button)
{
amPmView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("OnClickListener", "OnClickListener called");
if(v instanceof Button)
{
if(((Button) v).getText().equals("AM"))
{
((Button) v).setText("PM");
if (tp.getCurrentHour() < 12) {
tp.setCurrentHour(tp.getCurrentHour() + 12);
}
}
else{
((Button) v).setText("AM");
if (tp.getCurrentHour() >= 12) {
tp.setCurrentHour(tp.getCurrentHour() - 12);
}
}
}
}
});
}