Hello!
Setting display to spinner on the time picker in Android renders a clock in React Native 64. It works as expected in React Native 63. I have only tested on Android.
See this repo for a sample. Branch main uses RN 63 and works as expected. Branch rn-64 is exactly the same code, simply upgraded by running npx react-native upgrade
https://github.com/klandell/time-spinner-bug
Open the app on an Android device. Click show time spinner. On react native 63, it shows as a spinner. On react native 64 it shows as a clock.
Vanilla react native app, not Expo.
System:
OS: macOS 11.1
CPU: (8) x64 Intel(R) Core(TM) i5-8257U CPU @ 1.40GHz
Memory: 564.87 MB / 16.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 15.0.1 - /var/folders/bq/rv3dbnrd4gnfymg9n66rgdc80000gn/T/yarn--1615903404422-0.9955909284122346/node
Yarn: 1.22.10 - /var/folders/bq/rv3dbnrd4gnfymg9n66rgdc80000gn/T/yarn--1615903404422-0.9955909284122346/yarn
npm: 7.0.3 - /usr/local/bin/npm
Watchman: Not Found
Managers:
CocoaPods: 1.10.1 - /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms: iOS 14.4, DriverKit 20.2, macOS 11.1, tvOS 14.3, watchOS 7.2
Android SDK:
Android NDK: 21.0.6113669
IDEs:
Android Studio: 4.1 AI-201.8743.12.41.6953283
Xcode: 12.4/12D4e - /usr/bin/xcodebuild
Languages:
Java: 11.0.9 - /usr/bin/javac
npmPackages:
@react-native-community/cli: Not Found
react: 17.0.1 => 17.0.1
react-native: 0.64.0 => 0.64.0
react-native-macos: Not Found
npmGlobalPackages:
*react-native*: Not Found
datetimepicker version: 3.2
iOS / Android version: Samsung Galaxy S20e, Android 10.
yeah this is happening in react native 64 only on Android
I am getting SpinnerTimePickerDialog in static TimePickerDialog getDialog()... and display = SPINNER.

If I change:
private void fixSpinner(Context context, int hourOfDay, int minute, boolean is24HourView, RNTimePickerDisplay display) {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N && display == RNTimePickerDisplay.SPINNER) {
to
private void fixSpinner(Context context, int hourOfDay, int minute, boolean is24HourView, RNTimePickerDisplay display) {
if (display == RNTimePickerDisplay.SPINNER) {
It works.
My recommendation is to do:
private void fixSpinner(Context context, int hourOfDay, int minute, boolean is24HourView, RNTimePickerDisplay display) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && display == RNTimePickerDisplay.SPINNER) {
I'll set up a PR
:tada: This issue has been resolved in version 3.4.1 :tada:
The release is available on:
Your semantic-release bot :package::rocket:
@klandell please let us know if the issue is resolved in latest release and please test it on different android versions (not just the appearance but the actual function), thank you!
@vonovak @billnbell Thank you both for looking into this. I updated to the latest package in the rn-64 branch of the demo repo above to 3.4.1. Unfortunately, the app is now crashing with the following exception:
--------- beginning of crash
03-23 09:13:21.320 19282 19282 E AndroidRuntime: FATAL EXCEPTION: main
03-23 09:13:21.320 19282 19282 E AndroidRuntime: Process: com.awesomeproject, PID: 19282
03-23 09:13:21.320 19282 19282 E AndroidRuntime: java.lang.RuntimeException: java.lang.NoSuchFieldException: TimePicker
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at com.reactcommunity.rndatetimepicker.RNDismissableTimePickerDialog.fixSpinner(RNDismissableTimePickerDialog.java:104)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at com.reactcommunity.rndatetimepicker.RNDismissableTimePickerDialog.<init>(RNDismissableTimePickerDialog.java:63)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at com.reactcommunity.rndatetimepicker.RNTimePickerDialogFragment.getDialog(RNTimePickerDialogFragment.java:83)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at com.reactcommunity.rndatetimepicker.RNTimePickerDialogFragment.createDialog(RNTimePickerDialogFragment.java:112)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at com.reactcommunity.rndatetimepicker.RNTimePickerDialogFragment.onCreateDialog(RNTimePickerDialogFragment.java:41)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at androidx.fragment.app.DialogFragment.onGetLayoutInflater(DialogFragment.java:380)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at androidx.fragment.app.Fragment.performGetLayoutInflater(Fragment.java:1412)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:883)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:100)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at android.os.Looper.loop(Looper.java:237)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:8167)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: Caused by: java.lang.NoSuchFieldException: TimePicker
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at java.lang.Class.getField(Class.java:1604)
03-23 09:13:21.320 19282 19282 E AndroidRuntime: at com.reactcommunity.rndatetimepicker.RNDismissableTimePickerDialog.fixSpinner(RNDismissableTimePickerDialog.java:77)
Hmm, sorry about that. If you or someone else could look into this, that would be great, my time is limited now. In the mean time, im going to revert the fix because it was probably better before. Thanks.
Thanks. I'll try to take a look at this next week as my time is limited right now as well. Unless someone else gets to it first!
I was able to do a little bit of digging into this. From what I can tell so far the issue seems to be stemming from this code
activityContext.getResources().getIdentifier(
resourceName,
"style",
activityContext.getPackageName()
),
in the getDialog method of RNTimePickerDialogFragment which creates the RNDismissableTimePickerDialog.
This value is passed as the theme variable to the RNDismissableTimePickerDialog constructor here:
public RNDismissableTimePickerDialog(
Context context,
int theme,
@Nullable TimePickerDialog.OnTimeSetListener callback,
int hourOfDay,
int minute,
int minuteInterval,
boolean is24HourView,
RNTimePickerDisplay display
) {
super(context, theme, callback, hourOfDay, minute, minuteInterval, is24HourView, display);
fixSpinner(context, hourOfDay, minute, is24HourView, display);
}
In React native 63, int theme = 2131558599 during debugging. In React Native 64 int theme = 0.
I'm not sure of the reason yet.
I just inspected the react-native-0.63.4.aar file packaged with react native.
In react-native-0.63.4.aar -> res -> values -> values.xml I see the following.
<style name="SpinnerTimePickerDialog" parent="Theme.AppCompat.Light.Dialog" ns1:targetApi="lollipop">
<item name="android:timePickerStyle">@style/SpinnerTimePickerStyle</item>
</style>
<style name="SpinnerTimePickerStyle" parent="android:Widget.Material.Light.TimePicker" ns1:targetApi="lollipop">
<item name="android:timePickerMode">spinner</item>
</style>
These values do not exist in react-native-0.64.0.aar -> res -> values -> values.xml
This is the commit that removed the styles this library relied on:
https://github.com/facebook/react-native/commit/c8fed9e3858876c4e9cfe452a9f51c9241f82aad
Simply adding
<style name="SpinnerTimePickerDialog" parent="Theme.AppCompat.Light.Dialog">
<item name="android:timePickerStyle">@style/SpinnerTimePickerStyle</item>
</style>
<style name="SpinnerTimePickerStyle" parent="android:Widget.Material.Light.TimePicker">
<item name="android:timePickerMode">spinner</item>
</style>
to my styles.xml file fixed the issue.
Is there a recommended way of integrating this change into the this library? I removed ns1:targetApi="lollipop" from my styles.xml file because the parser was complaining about it. I assume that field is needed in the library though?
If someone with more familiarity with Android could weigh in it would be hugely helpful.
ah, so it's this: https://github.com/react-native-datetimepicker/datetimepicker/issues/258 becoming a real issue 6 months later 馃槅
Nice, thanks a lot for the investigation!
I removed ns1:targetApi="lollipop" from my styles.xml file because the parser was complaining about it
I'm assuming we should keep it. There probably is a commit in RN's history that explains what those things do and why they are there.
So if you add those things to the styles.xml file in this package that should probably fix it. The file does not exists but I'm guessing that android studio will have a way to create it or you can do it manually. Unfortunately, I'm not an android guru either but I think this should work.
Thanks again! :+1:
:tada: This issue has been resolved in version 3.4.3 :tada:
The release is available on:
Your semantic-release bot :package::rocket: