Reputation: 343
I have a TouchableOpacity and a TextInput inside a ScrollView, when the TextInput is focused an I press the TouchableOpacity I wanna fire first the onBlur and then the onPress. What happens? with keyboardShouldPersistTaps="never" the onPress won't execute at all and with "handled" the onBlur won't execute at all and the input won't lose focus. I noticed that with TouchableOpacity imported from 'react-native-gesture-handler' and not from 'react-native', and keyboardShouldPersistTaps to "never" both onPress and onBlur will execute but the problem here is that the onBlur comes after the onPress! Any solution?
<ScrollView keyboardShouldPersistTaps="never">
<TouchableOpacity onPress={() => console.log('press')}>
<Text>Click me</Text>
</TouchableOpacity>
<TextInput value={value} onBlur={() => console.log('blur')} />
</ScrollView>
expected output with field focused and pressing the touchable:
blur
press
edit: a more complicated scenario
//one component
<ScrollView keyboardShouldPersistTaps="handled">
<TextInput value={value} onBlur={() => console.log('blur')} />
<TextInput value={value} onBlur={() => console.log('blur')} />
<TextInput value={value} onBlur={() => console.log('blur')} />
</ScrollView>
//another component
<TouchableOpacity onPress={() => console.log('press')}>
<Text>Click me</Text>
</TouchableOpacity>
Both Components would be rendered inside a Bigger Component.
Upvotes: 5
Views: 2389
Reputation: 1006
You can use keyboardShouldPersistTaps="handled"
and manually fire blur
in onPress
handler. It is not perfect solution, but it may be enough.
import * as React from 'react';
import {
Text,
View,
StyleSheet,
ScrollView,
TouchableOpacity,
TextInput,
} from 'react-native';
import Constants from 'expo-constants';
export default function App() {
const [value, setValue] = React.useState();
const input = React.useRef();
return (
<View style={styles.container}>
<ScrollView keyboardShouldPersistTaps="handled">
<TouchableOpacity
onPress={() => {
input.current.blur();
console.log('press');
}}>
<Text>Click me</Text>
</TouchableOpacity>
<TextInput
ref={input}
value={value}
onBlur={() => console.log('blur')}
/>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
Edit: more complicated scenario - you can use Keyboard
module to dismiss keyboard, which will automatically fire blur event on your inputs.
import * as React from 'react';
import {
Text,
View,
StyleSheet,
ScrollView,
TouchableOpacity,
TextInput,
Keyboard,
} from 'react-native';
import Constants from 'expo-constants';
export default function App() {
const [value, setValue] = React.useState();
return (
<View style={styles.container}>
<ScrollView keyboardShouldPersistTaps="handled">
<TextInput value={value} onBlur={() => console.log('blur')} />
<TextInput value={value} onBlur={() => console.log('blur')} />
<TextInput value={value} onBlur={() => console.log('blur')} />
</ScrollView>
<TouchableOpacity
onPress={() => {
Keyboard.dismiss();
console.log('press');
}}>
<Text>Click me</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
Upvotes: 4