-
-
Notifications
You must be signed in to change notification settings - Fork 83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KeyboardAwareScrollView scroll to the top on android with multiline TextInput #708
Comments
Hi @NyoriK Thank you for the issue - I'm currently busy at my work, but I'll look into this problem. Thanks for sharing a minimal reproducible demo ❤️ |
@NyoriK Have you tried to use a bottomOffset for the KeyboardAwareScrollView equal or superior to the height of a line to see if it changes that behaviour ? Try with a large one to start just to see if it fixes it. |
@Jul1enF Does not fix it, still has the issue. @kirillzyusko Thank you. |
Hey @NyoriK I've tried to reproduce the problem on Pixel 8 Pro (API 35, emulator) and Pixel 7 Pro (API 35, real device) and couldn't reproduce it: aware-scroll-view-works-as-expected.movAny ideas what is the difference between our setups? 🤔 I'm testing the package from |
After your comment, I tried again (just now), and this time with default create expo app template. But I still have the same issue. Below are the steps: 1. npx create-expo-app@latest keyboard-controller-test-project Creating an Expo project using the default template. 2. cd keyboard-controller-test-project 3. npx expo install react-native-keyboard-controller 4. npm run reset-project 5. npx expo run:android --device ✔ Created native directory 6. Add project/components/TestForm.tsx:
7. Update project/app/index.tsx:
8. Update project/app/_layout.tsx:
9. npx expo start -c (just to be on the safe side) Android Xiaomi Redmi Note 10 Pro (device): android-device-test.movAndroid Pixel_8_API_35 (emulator): android-emulator-test.movproject/package.json:
|
@NyoriK oki-doki, may I ask you to upload your reproduction project to the github so that I can clone it and run it locally? |
Thanks @NyoriK With 50/50 chances I can actually reproduce a problem. After a quick look it seems like handlers can not be attached 🤔 Trying to figuring out what's going wrong! |
Okay @NyoriK I think it's because of In a meantime I'll try to fix the issue in |
@kirillzyusko Thanks for the suggestion to try react-native-screens@3.35.0. I attempted to downgrade but ran into dependency conflicts because my project uses:
When I tried to install react-native-screens@3.35.0 and @react-navigation/native@6.x.x, npm showed dependency resolution errors due to these requirements. Downgrading would require:
This would be a major breaking change for the project. Could we explore a fix that works with react-native-screens v4? Or perhaps there are other workarounds we could try? |
Update: I did some additional testing with an older setup:
Here's the package.json for reference:
android-good-expo-older-version.mov
android-bad-expo-old.mov
ios-scrollenabled-false-bad-expo-old.mp4 |
At the moment fields that occupy entire screen may not work correctly, because current I'm going to re-implement this component and rely on caret position to be sure that actually caret is in visible area and not entire field.
Did you just specify
When I mounted Let me know if you have any further questions 😊 |
About the iOS behavior - the scrolling issue occurs with
About the async KeyboardProvider mounting - that's an interesting workaround. Would you be willing to share more details about how you tested this? I'd be happy to try it out and provide feedback on different scenarios. |
That was a quite primitive code, something like: const [shouldMountKeyboardProvider, setMountKeyboardProvider] = useState(false);
useEffect(() => {
setTimeout(() => {
setMountKeyboardProvider(true);
}, 16);
}, []);
return shouldMountKeyboardProvider ? <KeyboardProvider>...</KeyboardProvider> : null; Feel free to experiment with that 🙌 Maybe it helped only in my case 😅 Alternatively you can try to remove |
@kirillzyusko Ahaa! Thanks for sharing the async mounting code! I tried it:
It does improve the behavior a lot - however if observing closely, I can still see the scroll does go to the top and comes back like before, but it's so fast that it's not immediately noticeable. It manifests as a quick stutter when scrolling down to the next line rather than the obvious scroll-to-top behavior we saw previously. |
@kirillzyusko I've tested PR #744 on both iOS and Android. Here are my findings:
keyboard-controller-pr-744.mp4
keyboard-controller-pr-744-jerk.mp4
The fix definitely improves the original behavior - the extreme scroll-to-top issue is gone. The remaining stutters are much less noticeable than the original problem, though they become more apparent with certain typing patterns. |
Well, it's kind of explainable. I'll start with input 5. It seems like input 5 grows with a delay. When you move a caret to a new line:
In paper example project the input grows as soon as you pressed "Enter" (can't test Fabric because suddenly input doesn't grow there at all - need to look into it): telegram-cloud-document-2-5426846321304701558.mp4The code example that I used can be found at: https://github.com/kirillzyusko/react-native-keyboard-controller/blob/main/example/src/screens/Examples/AwareScrollView/index.tsx I think if you manage your input to grow immediately when you press "Enter" it will work fine (in the same way as on iOS, because I'm more than sure, that iOS stretches input immediately without a need to type a new character). Maybe it's Fabric specific bug 🤷♂️
I'll try to investigate it today 👍 |
## 📜 Description Execute monkey-patch applying earlier than `StatusBar` modifications. ## 💡 Motivation and Context It happens when `KeyboardProvider` had direct child as `StatusBar` - and such thing can happen in `expo-router`, for example: https://github.com/expo/expo/blob/5f40a80019bb6b892eda94dd244fdc0df8880ccb/packages/expo-router/src/ExpoRoot.tsx#L57 To prevent this problem I'm executing monkey patch applying in "layout effect" instead of plain "effect". This gives me a precious time and an ability to apply patch earlier and thus re-direct a call to my module. And if we dig a little bit deeper. When `KeyboardProvider` gets mounted the `useLayoutEffect` will be fired after component mount. On contrast `StatusBar` will try to change its properties in `componentDidMount`. And technically `componentDidMount` will be executed first (before `useLayoutEffect`). But `StatusBar` schedules update via `setImmediate` and `setImmediate` will execute its callback after `useLayoutEffect`, so this fix should work 🙂 Closes #708 #587 ## 📢 Changelog ### Android - apply monkey patch in layout effect to be sure monkey patch can be applied earlier than first call to `StatusBar` module (if `KeyboardProvider` and `StatusBar` were mounted simultaneously). ## 🤔 How Has This Been Tested? Tested manually in https://github.com/NyoriK/keyboard-controller-test-project ## 📸 Screenshots (if appropriate): https://github.com/user-attachments/assets/6e259ffe-de59-46a6-b9a6-26de05698b06 ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed
@kirillzyusko Thanks for the detailed investigation! Your analysis of the asynchronous layout update behavior matches exactly what I'm seeing: I agree with your suggestion to:
Would you like me to create the new issue focusing specifically on the async layout updates and stuttering? I can include the same details and videos you shared, focusing on this specific behavior. |
Yes, please do 🙏 |
Describe the bug
I am using KeyboardAwareScrollView for my form, and all the TextInputs have multiline enabled.
When the caret position reach near the keyboard and at the caret position at the end of the line, by typing a character, it scrolls to the top, and again after typing the next character, it scrolls back to the current caret position view.
This happens even on the first TextInput if the caret position reaches near the keyboard.
Code snippet
Setting up the project.
project/app/_layout.tsx:
project/app/index.tsx:
project/components/TestForm.tsx:
To Reproduce
Steps to reproduce the behavior:
Go to Input 5
Write till the caret position reaches the end of line, and type a single character
It will scroll up to the top
Then type again,
It will scroll down to the current caret position view.
Go to input 1
Write till the caret position reach near the keyboard, and and type a character
It will scroll up to the top
Then type again, and it will scroll down to the current caret position view.
Expected behavior
It should not scroll to the top.
Screenshots
VID_20241128_035422.mp4
Desktop OS: MacOs Sonoma
Device: Redmi Note 10 Pro and
Emulator: Pixel 8
react: 18.3.1
react-native: 0.76.3
expo: ~52.0.11
react-native-reanimated: ~3.16.1
expo-router: ~4.0.9
react-native-keyboard-controller: ^1.14.5
The text was updated successfully, but these errors were encountered: