kirillzyusko / react-native-keyboard-controller

Keyboard manager which works in identical way on both iOS and Android
https://kirillzyusko.github.io/react-native-keyboard-controller/
MIT License
1.71k stars 73 forks source link

useReanimatedKeyboardAnimation on iOS doesn't run animation when closing keyboard #670

Open billnye2 opened 2 days ago

billnye2 commented 2 days ago

Describe the bug Hello, first off really great library! I am not sure what we would all do without devs like you spending your free time making libs that are required for a good user experience but that don't come built into react native.

I am using useReanimatedKeyboardAnimation to animate my view and it works just great on Android, open and close animation works well. On iOS, the open animation works fine too, with my view animating up. But when closing the keyboard on iOS, the view instantly goes down instead of animating with the keyboard.

I noticed this comment you made describing using useKeyboardHandler to manually track keyboard height/progress. When I switched to using that, the keyboard animations were smooth on both Android and now on iOS too, for both open and close. So for now I am using this hook. But I wanted to bring to your attention that useReanimatedKeyboardAnimation appears to not work correctly for iOS close animations.

I looked into the code of this lib and think it may have something to do with this line of code not containing 'ios' in the list of platforms (only has android right now).

Oh I should also point out this was all tested in the iOS Simulator.

Want to hear something else interesting and wacky? So, base case, when I use Keyboard.dismiss or tap on a ScrollView to dismiss the keyboard, it instantly shifts my view down instead of animating. This is the bug right. BUT, in the iOS Simulator, while the on-screen keyboard is open, if I go to "I/O" -> "Keyboard" -> "Connect hardware keyboard", then the on-screen keyboard will dismiss (because I told it I'm going to use a real keyboard so it doesn't need the on-screen one). When this happens, IT DOES ANIMATE ON CLOSE! Wacky behavior. Maybe this is all just the iOS Simulator being buggy.

Repo for reproducing Can add if required.

Expected behavior Keyboard close animation works on iOS too.

kirillzyusko commented 1 day ago

Hello @billnye2 👋

Thank you for raising this issue. Let me dive a little bit in the history of development of this library, so you can better understand what happens underhood and why it works in such way now.


1️⃣ 1.0-1.3 era

Starting from 1.0.0 till 1.3.0 this library could animate only simple animations (mostly translateY). And iOS and Android works differently:

2️⃣ 1.4-1.10 era

Later on, I discovered, that such iOS layout animations doesn't work in some cases:

So in the end I crafted useKeyboardHandler which aimed to fix all these issues.

And in fact this new API solved all these issues except one single big problem - the animation in onMove was always one frame behind 😡

3️⃣ 1.11 era

The issue that you opened was already described in https://github.com/kirillzyusko/react-native-keyboard-controller/issues/307 Back to the times I fixed it like https://github.com/kirillzyusko/react-native-keyboard-controller/pull/400

And I thought it's a pretty decent fix. But later on I discovered, that this fix may introduce even bigger lags when we animate non-UI props...

4️⃣ 1.12 - present era

Starting from 1.12 I fixed the issue that was introduced in 1.4, i. e. one frame delay - https://github.com/kirillzyusko/react-native-keyboard-controller/pull/412

However I had to remove the layout animations, because if I would continue to schedule them additionally then I would end up in a case when we still have one frame delay 🤔


So, what we have now - if you are animating non-UI props (such as height/width), then you may end up in a situation when some transitions (i. e. when you call Keyboard.dismiss() (when you tap on a ScrollView to close a keyboard it'll call Keyboard.dismiss() underhood anyway)) are not animated properly.

My recommendation here would be to stick to the usage of useKeyboardHandler in such cases. Of course a rhetorical question may arise 👇

Why useReanimatedKeyboardAnimation hook can not be fixed?

I would like to give users a freedom in choosing what they want to achieve. If they want to have a fully native behavior driven by iOS, then they can use useReanimatedKeyboardAnimation that will heavily depend from the iOS behavior and it will run absolutely smooth animations.

If you want to go in a non-native approach, then you can use useKeyboardHandler, but it's kind of developer choice and they should know what they are doing. Don't get me wrong - useKeyboardHandler also gives a very good performance and produced animations will still be very smooth. But when you are using this hook, you need to keep in mind, that you are getting a control of every frame of the animation, which is not very specific to iOS.


P. S. from what I tested i can say, that useReanimatedKeyboardAnimation should work on a new architecture perfectly, even when you close the keyboard via Keyboard.dismiss(). So maybe it's just a bug of old architecture 🤷‍♂️ Do you use old or new architecture?

billnye2 commented 14 hours ago

Wow! Thank you for that great answer. That must've taken ages to write. Really appreciate the effort you put into your work.

That all makes a lot of sense. It's cool to see what goes on behind the scenes and really how difficult it is to get close-enough cross platform behavior. Yup when I was researching this I came across those issues and saw the history and thought perhaps there had been some changes since then. I will use useKeyboardHandler because that gives perfect behavior for me.

To answer your question, I am currently using old architecture on Expo 51. Expo 52 makes the new architecture the default for new projects I believe, so once that is stable and out for a few months, I'll try it. I expect lots of libraries still need updating to the new arch.

Thanks!