-
-
Notifications
You must be signed in to change notification settings - Fork 82
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
Fails to avoid keyboard if TextInput
is focused while keyboard is closing
#516
Comments
@thisisgit have you tried to add If the problem even with |
@kirillzyusko You're right, However it's a different story if we would want to support
Therefore I would also prefer to not close the keyboard when Now I see that I should have added this in the |
@thisisgit you are right with In your example you were using single line inputs, so I thought that Do I correctly understand that you are using |
@kirillzyusko Yup, to summarize:
Simulator.Screen.Recording.-.iPhone.15.-.2024-07-22.at.19.37.42.mp4
Simulator.Screen.Recording.-.iPhone.15.-.2024-07-22.at.19.39.31.mp4And here's the updated code of `multiline={true}` & `blurOnSubmit={true}`import React, { useCallback, useEffect, useRef, useState } from 'react';
import { FlatList, ListRenderItemInfo, StyleSheet } from 'react-native';
import { TextInput } from 'react-native-gesture-handler';
import { KeyboardAwareScrollView } from 'react-native-keyboard-controller';
type ListItem = {
id: string;
text: string;
};
const DATA: ListItem[] = [
{
id: '1',
text: 'Test1',
},
{
id: '2',
text: 'Test2',
},
{
id: '3',
text: 'Test3',
},
{
id: '4',
text: 'Test4',
},
{
id: '5',
text: 'Test5',
},
{
id: '6',
text: 'Test6',
},
{
id: '7',
text: 'Test7',
},
];
type Props = ListItem & {
isFocused: boolean;
onSubmit: () => void;
};
const Item = ({ id, text, isFocused, onSubmit }: Props) => {
const inputRef = useRef<TextInput | null>(null);
useEffect(() => {
if (isFocused) {
inputRef.current?.focus();
}
}, []);
return (
<TextInput
ref={inputRef}
style={styles.input}
defaultValue={text}
multiline={true}
blurOnSubmit={true}
onSubmitEditing={onSubmit}
/>
);
};
export const TestKeyboardAwareList = () => {
const [data, setData] = useState<ListItem[]>(DATA);
const addedItemIdRef = useRef<string | undefined>();
const addAndFocus = useCallback(() => {
// Using setTimeout to simulate adding new item via API request
setTimeout(() => {
const newItemId = new Date().getTime().toString();
addedItemIdRef.current = newItemId;
setData((prev) => [...prev, { id: newItemId, text: '' }]);
}, 100);
}, []);
const renderItem = useCallback(
({ item }: ListRenderItemInfo<ListItem>) => {
const isFocused = addedItemIdRef.current === item.id;
return <Item {...item} isFocused={isFocused} onSubmit={addAndFocus} />;
},
[addAndFocus]
);
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.id}
keyboardDismissMode={'interactive'}
renderScrollComponent={(props) => {
return <KeyboardAwareScrollView {...props} />;
}}
/>
);
};
const styles = StyleSheet.create({
input: {
height: 80,
borderWidth: 1,
width: '100%',
fontSize: 24,
},
}); |
@thisisgit thank you for such detailed explanation! I debugged your code. The problem comes to the fact that view is not laid out on a native side when you set a focus: {
"eventName": "onFocusedInputLayoutChanged",
"layout": {
"absoluteX": 0, "absoluteY": 59.666666666666664, "height": 0, "width": 0, "x": 0, "y": 0
},
"parentScrollViewTarget": 3327,
"target": 3379
} I slightly modified your code: setTimeout(() => {
if (isFocused) {
inputRef.current?.focus();
}
}, 16); And now it works properly. Can you check on your side whether such code produces acceptable result for you? I'm thinking on how to handle such cases on a native side, but don't have any ideas at the moment because current codebase heavily relies on the fact that we can measure Anyway - curious to hear whether such workaround works for you (i. e. to add 16ms on JS before |
@kirillzyusko I tried adding 16ms timeout on both above example and on my app and can confirm that it's working good 👍 I wasn't suspecting view not laid on the native side at all since focus event is being triggered in const addAndFocus = useCallback(() => {
// setTimeout(() => {
// const newItemId = new Date().getTime().toString();
// addedItemIdRef.current = newItemId;
// setData((prev) => [...prev, { id: newItemId, text: '' }]);
// }, 100);
// Removing setTimeout here avoids the keyboard
const newItemId = new Date().getTime().toString();
addedItemIdRef.current = newItemId;
setData((prev) => [...prev, { id: newItemId, text: '' }]);
}, []); Simulator.Screen.Recording.-.iPhone.15.-.2024-07-22.at.23.58.54.mp4Or giving const addAndFocus = useCallback(() => {
setTimeout(() => {
const newItemId = new Date().getTime().toString();
addedItemIdRef.current = newItemId;
setData((prev) => [...prev, { id: newItemId, text: '' }]);
// Or give longer timeout to wait for keyboard to dismiss completely
}, 500);
}, []); Simulator.Screen.Recording.-.iPhone.15.-.2024-07-23.at.00.02.12.mp4Note that I didn't apply the 16ms timeout fix in above examples. That's why I was suspecting maybe the issue is coming from when trying to measure Anyways, thanks to you, I'll stick to the 16ms solution. I also found out calling But I'm curious, isn't view supposed to be already laid out in the native side when |
I think you can create an additional ref and call the function only one time (after that change ref value to
Well, this is my understanding as well (like view should be mounted and laid out) 🤷♂️ I had "similar" issue in #491 - there I also had to miss one frame to properly pick up selection coordinates when multiline input grows. Maybe a problem (as you pointed out earlier) comes from the fact, that So I think calling a |
@thisisgit Look what I found: facebook/react-native#33653 Seems like you may have |
@kirillzyusko This is AWESOME! Thank you so much for finding this! I thought this would be the best solution since it also fixes the keyboard flickering issue. And... you found it! It was little tricky to find out on how to use the added feature since that But it worked just fine when I tried it: <TextInput
ref={inputRef}
style={styles.input}
defaultValue={text}
multiline={true}
// This!
submitBehavior={'submit'}
onSubmitEditing={onSubmit}
/> Simulator.Screen.Recording.-.iPhone.15.-.2024-07-23.at.14.19.25.mp4Found out that the PR didn't include Typescript support so I created a PR on react-native to support it and hope it gets merged ASAP without any issue. Meanwhile, I'll just suppress the type error. Again, I really appreciate your help on resolving issues that is out-of-scope of this library 🙏 I'll close this issue as multiple solutions have been suggested. |
@thisisgit nice! Would be good to submit a PR to the documentation website as well I think 🙃 New demo from UI perspective looks much better 😍 It looks exactly like it should work! |
@kirillzyusko Yup I'll check on the website once this gets merged since there may be something that I'd be missing. Thanks! |
@thisisgit I think your PR was already merged 🙃 It was imported on a Phabricator, so now it's only a technical aspect when your PR will update the status on GitHub 👀 |
@kirillzyusko Oh thanks for letting me know. It's a lot quicker than I thought😮 I'll come back and check the website once I'm done with some urgent tasks. Probably at most this weekend? |
@thisisgit yeah, sure, take your time 😊 |
Describe the bug
Hi, in a list of
TextInput
s, what I'm trying to achieve here is to create new item and focus it when return key is pressed from the keyboard.This results in closing initially opened keyboard since
blur
is triggered when return key is pressed, and reopen the keyboard after new item is added and focused.Newly added
TextInput
seems to avoid the keyboard just fine if the time between closing the keyboard and focusing newTextInput
is very short, but once there's a delay in between those two actions, it doesn't avoid the keyboard.The delay can be caused due to:
To simulate and reproduce this bug, I gave
setTimeout
of 100ms before adding new item. You can check it onaddAndFocus
function of below code.I'm also posting a recorded video of this so I believe it'll be a lot easier to understand the issue by checking the video first.
Code snippet
Repo for reproducing
Import above component in any screen
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Added item should avoid the keyboard
Screenshots
Simulator.Screen.Recording.-.iPhone.15.-.2024-07-22.at.17.52.29.mp4
Smartphone (please complete the following information):
Additional context
n/a
The text was updated successfully, but these errors were encountered: