mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Fix DatePickerAndroid with mode spinner on Android Nougat(7.0) (#24739)
Summary: When mode is spinner in Android Nougat the DatePicker shows calendar I got it from https://gist.github.com/jeffdgr8/6bc5f990bf0c13a7334ce385d482af9f and did some adjustments in order to work with `DatePicker`. Workaround for this bug: https://code.google.com/p/android/issues/detail?id=222208. In Android 7.0 Nougat, spinner mode for the DatePicker in DatePickerDialog is incorrectly displayed as calendar. ## Changelog [Android][Fixed] Fix date picker with mode spinner on Android Nougat (7.0) Pull Request resolved: https://github.com/facebook/react-native/pull/24739 Differential Revision: D15391354 Pulled By: cpojer fbshipit-source-id: 09f45367250aa14857a9c68846c7f2ce7c49ee3b
This commit is contained in:
committed by
Facebook Github Bot
parent
cf9babf082
commit
bb060d6cf8
+70
-3
@@ -7,12 +7,16 @@
|
||||
|
||||
package com.facebook.react.modules.datepicker;
|
||||
|
||||
import android.app.DatePickerDialog;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.app.DatePickerDialog;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.DatePicker;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -33,6 +37,7 @@ public class DismissableDatePickerDialog extends DatePickerDialog {
|
||||
int monthOfYear,
|
||||
int dayOfMonth) {
|
||||
super(context, callback, year, monthOfYear, dayOfMonth);
|
||||
fixSpinner(context, year, monthOfYear, dayOfMonth);
|
||||
}
|
||||
|
||||
public DismissableDatePickerDialog(
|
||||
@@ -43,6 +48,7 @@ public class DismissableDatePickerDialog extends DatePickerDialog {
|
||||
int monthOfYear,
|
||||
int dayOfMonth) {
|
||||
super(context, theme, callback, year, monthOfYear, dayOfMonth);
|
||||
fixSpinner(context, year, monthOfYear, dayOfMonth);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,4 +59,65 @@ public class DismissableDatePickerDialog extends DatePickerDialog {
|
||||
super.onStop();
|
||||
}
|
||||
}
|
||||
|
||||
private void fixSpinner(Context context, int year, int month, int dayOfMonth) {
|
||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
|
||||
try {
|
||||
// Get the theme's android:datePickerMode
|
||||
final int MODE_SPINNER = 2;
|
||||
Class<?> styleableClass = Class.forName("com.android.internal.R$styleable");
|
||||
Field datePickerStyleableField = styleableClass.getField("DatePicker");
|
||||
int[] datePickerStyleable = (int[]) datePickerStyleableField.get(null);
|
||||
|
||||
final TypedArray a = context.obtainStyledAttributes(null, datePickerStyleable, android.R.attr.datePickerStyle, 0);
|
||||
Field datePickerModeStyleableField = styleableClass.getField("DatePicker_datePickerMode");
|
||||
int datePickerModeStyleable = datePickerModeStyleableField.getInt(null);
|
||||
final int mode = a.getInt(datePickerModeStyleable, MODE_SPINNER);
|
||||
a.recycle();
|
||||
|
||||
if (mode == MODE_SPINNER) {
|
||||
DatePicker datePicker = (DatePicker) findField(DatePickerDialog.class, DatePicker.class, "mDatePicker").get(this);
|
||||
Class<?> delegateClass = Class.forName("android.widget.DatePickerSpinnerDelegate");
|
||||
Field delegateField = findField(DatePicker.class, delegateClass, "mDelegate");
|
||||
Object delegate = delegateField.get(datePicker);
|
||||
Class<?> spinnerDelegateClass;
|
||||
spinnerDelegateClass = Class.forName("android.widget.DatePickerSpinnerDelegate");
|
||||
|
||||
// In 7.0 Nougat for some reason the datePickerMode is ignored and the delegate is DatePickerClockDelegate
|
||||
if (delegate.getClass() != spinnerDelegateClass) {
|
||||
delegateField.set(datePicker, null); // throw out the DatePickerClockDelegate!
|
||||
datePicker.removeAllViews(); // remove the DatePickerClockDelegate views
|
||||
Method createSpinnerUIDelegate = DatePicker.class.getDeclaredMethod("createSpinnerUIDelegate", Context.class, AttributeSet.class, int.class, int.class);
|
||||
createSpinnerUIDelegate.setAccessible(true);
|
||||
|
||||
// Instantiate a DatePickerSpinnerDelegate throughout createSpinnerUIDelegate method
|
||||
delegate = createSpinnerUIDelegate.invoke(datePicker, context, null, android.R.attr.datePickerStyle, 0);
|
||||
delegateField.set(datePicker, delegate); // set the DatePicker.mDelegate to the spinner delegate
|
||||
datePicker.setCalendarViewShown(false);
|
||||
// Initialize the date for the DatePicker delegate again
|
||||
datePicker.init(year, month, dayOfMonth, this);
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user