Text in FlatList is not selectable on Android - react-native

I just upgraded my app from React Native 0.58.5 to 0.61.2 and now I can't select text in FlatList on Android.
I tried to set the selectable = {true} in the Text component in React Native 58.5, and it worked well and could copy the content in the Text.
But after upgraded the React Native version from 0.58.5 to 0.61.2, and couldn't select the text for copy/paste the content in Android 9.0.
Actually it worked on Android 5.0, but didn't work on Android 9.0
export default class App extends React.Component {
_renderItem = ({item}) => {
return (
<View>
<Text selectable>{item}</Text>
</View>
)
}
_keyExtractor = (item, index) => index.toString();
render() {
return (
<View style={styles.container}>
<Text selectable>This is selectable Text...</Text>
<FlatList
data={['not selectable text', 'not selectable text']}
renderItem={this._renderItem}
keyExtractor={this._keyExtractor}
/>
</View>
);
}
}
Expected behavior: Text in Flatlist should be selectable.
Current behavior: Can't select the Text component even though set the selectable={true} in Android 9.0

I solved this by adding a key prop to the Text component:
<Text selectable={true} key={Math.random()}>
{text}
</Text>
EDIT: The solution above does not seem to work on all RN versions, an alternative solution is setting removeClippedSubviews={false} on the FlatList

You should enclose this into touchableopacity..
<TouchableOpacity style={{ flex: 1 }}
onPress={() =>}}>
<View>
<Text selectable>{item}</Text>
</View>
</TouchableOpacity>

Related

React native List footer component not rendering(funtion component)

I am trying to achieve pagination for infinite scrolling in react native. When loading, I want to render the loading spinner at the bottom of the Flat list component. (Note: I'm using Expo for this app)
const renderFooter = () => {
if (!category.loading) return null;
return (
<View style={spinnerStyles.container}>
<ActivityIndicator animating size="large" color="#0000ff" />
</View>
);
};
return (
<View style={styles.container}>
<FlatList
columnWrapperStyle={{ justifyContent: "space-between" }}
numColumns={2}
data={category.data}
renderItem={categoryItem}
keyExtractor={(item) => item._id + item.sub_category}
onEndReachedThreshold={0}
listFooterComponent={renderFooter}
onEndReached={() => loadMore()}
/>
</View>
);
The loading spinner not correctly working with the flat list footer.
Has anyone run into this issue before, or does anyone have a solution?
Sorry, it's my simple syntax error. It's actually ListFooterComponent not listFooterComponent. Now it's working fine, Thank you.
Instead of calling the refrence, call the function. It should look something like this.
ListFooterComponent={renderFooter()}

Vertically align Pressable inside a Text component

<View
style={{
flexDirection: "row",
}}
>
<Text
style={{
flex: 1,
}}
>
By continuing, you agree to our{" "}
<Pressable
onPress={...}
>
<Text>
Terms of Service
</Text>
</Pressable>
</Text>
</View>
"Terms of Service" is printed higher than "By continuing, you agree to our". How do I vertically align them?
Or more precisely - how do I get the Pressable Text to vertically align to the bottom?
This is a bug in React Native itself. There are several open reports of this bug on React Native's GitHub, but the chances of it being fixed don't look good:
https://github.com/facebook/react-native/issues/30375 - for the general problem of Views nested in Text being mis-aligned on Android, and a core contributor responded, but appeared to get derailed and stuck in some details specific to mimicking superscript and subscript.
https://github.com/facebook/react-native/issues/31955 - specific to Pressable and someone posted a PR to fix it, but Facebook closed it because no-one from Facebook got around to reviewing it before it became stale and out of date with the main branch.
There's also some discussion in this issue comment, but the issue got closed.
In React Native >= 0.65, if your inline pressable element uses only text styles, you can work around this issue by using <Text> with onPress (and onPressIn and onPressOut to style the pressed state). Crude example:
/**
* Like a simplified Pressable that doesn't look broken inline in `Text` on Android
*/
const TextButton = ({ children, onPress, style, ...rest } => {
const [pressed, setPressed] = useState(false)
const onPressIn = () => setPressed(true)
const onPressOut = () => setPressed(false)
return (
<Text
onPress={onPress}
onPressIn={onPressIn}
onPressOut={onPressOut}
style={typeof style === 'function' ? style({ pressed }) : style}
{...rest}
>
{typeof children === 'function' ? children({ pressed }) : children}
</Text>
)
}
Beware, however, that there are also bugs around selecting interactive elements nested inside text using accessibility tools. If you can simply avoid nesting the interactive element in text, and have it on its own line, that's probably better: link-like interactive nested text isn't well supported in React Native currently.
On older versions of React Native before 0.65, Text didn't support onPressIn or onPressOut:
If you don't need Pressable's pressed state, use Text instead of Pressable (as the asker did: https://stackoverflow.com/a/66590787/568458)
If you do need pressed state, Text doesn't support the required onPressIn/Out handlers. However, TouchableWithoutFeedback does support those, and works by injecting props into its child so the Text will remain Text with no wrapping View. Wrap a Text in TouchableWithoutFeedback and pass the touchable onPress with onPressIn and onPressOut handlers and store the pressed state yourself.
/**
* Like a simplified Pressable that doesn't look broken inline in `Text` on Android
*/
const TextButton = ({ children, onPress, style, ...rest } => {
const [pressed, setPressed] = useState(false)
const onPressIn = () => setPressed(true)
const onPressOut = () => setPressed(false)
// TouchableWithoutFeedback modifies and returns its child; this returns `Text`
// plus press in/out events attached that aren't supported by Text directly.
return (
<TouchableWithoutFeedback
onPress={onPress}
onPressIn={onPressIn}
onPressOut={onPressOut}
>
<Text
style={typeof style === 'function' ? style({ pressed }) : style}
{...rest}
>
{typeof children === 'function' ? children({ pressed }) : children}
</Text>
</TouchableWithoutFeedback>
)
}
Warning: if you're also using React Native Web and React Navigation, don't use the TouchableWithoutFeedback approach on Web, use pure Pressable on web, because React Navigation's navigate functions don't reliably work when passed to Touchable*s on Web due to a quirk of how the event handlers are set up (but they do work in Pressable), and this issue doesn't exist on Web.
Ended up doing this differently, using the onPress property of the <Text> component and finally wrapping all <Text> components in another <Text> component to have a proper line break:
<View>
<Text>
<Text>
By continuing, you agree to our{" "}
</Text>
<Text onPress={() => {...}}>
Terms of Service
</Text>
<Text>
{" "}and our{" "}
</Text>
<Text onPress={() => {...}}>
Privacy Policy
</Text>
</Text>
</View>
The snippet below should work but hard to understand without giving a shot. If you can provide screenshots I can help more in sake of getting a more proper result.
<View>
<Text style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center'
}}>
By continuing, you agree to our{" "}
<Pressable
onPress={() => {
navigate("LegalStack", { screen: "Terms" });
}}
>
<Text style={{margin: 'auto'}}>
Terms of Service
</Text>
</Pressable>
</Text>
</View>
I found a very hackidy-hack solution...
<Text selectable={true}>
<Text>if you click</Text>
<TouchableOpacity
style={{flexDirection: 'row'}}
onPress={() => Linking.openURL("https://www.google.com")}
>
<Text
style={{
alignSelf: 'flex-end',
marginBottom: -4,
}}
>
here
</Text>
</TouchableOpacity>
<Text>, it will open google</Text>
</Text>
By default the flexDirection is column. Change it to flexDirection:"row"

react native text input with required asterisk symbol similar to material ui

Please share samples in react native
text input with required asterisk symbol similar to material ui
enter image description here
Use react-native-paper
<TextInput
label='Password '
mode='outlined'
value={this.state.text}
onChangeText={password => this.setState({ password })}
underlineColor='transparent'
theme={...}
>
More detail Here
I have used "react-native-paper": "4.9.2" below code works fine in this version.
<TextInput
mode="flat"
label={
<Text>
Label
<Text style={{color: 'red'}}> *</Text>
</Text>
}
placeholder="Type something"
/>
Or, if you prefer, create a component for that:
import React from 'react';
import { Text } from 'react-native';
export default function InputLabel({ label, style={}, required=false }) {
return (
<Text style={style}>
{label}
{required && <Text style={{ color: 'red' }}> *</Text>}
</Text>
);
}

React native onPress with TouchableWithoutFeedback is not working

I am developing a simple React Native application for learning purpose. I am just taking my initial step to get into the React Native world. But in this very early stage, I am having problems. I cannot get a simple touch event working. I am implementing touch event using TouchableWithoutFeedback. This is my code.
class AlbumList extends React.Component {
constructor(props)
{
super(props)
this.state = {
displayList : true
}
}
componentWillMount() {
this.props.fetchAlbums();
}
albumPressed(album)
{
console.log("Touch event triggered")
}
renderAlbumItem = ({item: album}) => {
return (
<TouchableWithoutFeedback onPress={this.albumPressed.bind(this)}>
<Card>
<CardSection>
<Text>{album.artist}</Text>
</CardSection>
<CardSection>
<Text>{album.title}</Text>
</CardSection>
</Card>
</TouchableWithoutFeedback>
)
}
render() {
let list;
if (this.state.displayList) {
list = <FlatList
data={this.props.albums}
renderItem={this.renderAlbumItem}
keyExtractor={(album) => album.title}
/>
}
return (
list
)
}
}
const mapStateToProps = state => {
return state.albumList;
}
const mapDispatchToProps = (dispatch, ownProps) => {
return bindActionCreators({
fetchAlbums : AlbumListActions.fetchAlbums
}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(AlbumList);
As you can see, I am implementing touch event on the list item. But it is not triggering at all when I click on the card on Simulator. Why? How can I fix it?
You should wrap your content in component like this:
<TouchableWithoutFeedback>
<View>
<Your components...>
</View>
</TouchableWithoutFeedback>
TouchableWithoutFeedback always needs to have child View component. So a component that composes a View isn't enough.
So instead of
<TouchableWithoutFeedback onPressIn={...} onPressOut={...} onPress={...}>
<MyCustomComponent />
</TouchableWithoutFeedback>
use:
<TouchableWithoutFeedback onPressIn={...} onPressOut={...} onPress={...}>
<View>
<MyCustomComponent />
</View>
</TouchableWithoutFeedback>
See the github issue for more info
Can be used with <TouchableOpacity activeOpacity={1.0}> </TouchableOpacity>
For those who struggle with this issue in react-native 0.64, and wrapping it in just a View doesn't work, try this:
<TouchableWithoutFeedback onPress={onPress}>
<View pointerEvents="none">
<Text>Text</Text>
</View>
</TouchableWithoutFeedback>
In my case i accidentally imported TouchableWithoutFeedback from react-native-web instead of react-native. After importing from react-native everything worked as expected.
In more recent React Native versions, just use Pressable instead:
https://reactnative.dev/docs/pressable
In my case, there was a shadow underneath, which caused instability. What I did to solve it was quite simple: zIndex: 65000
<View style={{ zIndex: 65000 }}>
<TouchableWithoutFeedback onPressIn={() => {}>
<View>
</View>
</TouchableWithoutFeedback>
</View>

React Native clear text multiple TextInput boxes

I found example code on a facebook React Native page which shows how to use setNativeProp to clear text on a click but I can't see how to do it with multiple text boxes. Here is the code:
var App = React.createClass({
clearText() {
this._textInput.setNativeProps({text: ''});
},
render() {
return (
<View style={styles.container}>
<TextInput ref={component => this._textInput = component}
style={styles.textInput} />
<TouchableOpacity onPress={this.clearText}>
<Text>Clear text</Text>
</TouchableOpacity>
</View>
);
}
});
The ref seems to be fixed in the function so will always target the same TextInput box. How can I alter the function to target any TextInput box I indicate?
This should work. Notice that the ref on the TextInput needs to be the one you call from the clearText functino.
var App = React.createClass({
clearText(fieldName) {
this.refs[fieldName].setNativeProps({text: ''});
},
render() {
return (
<View style={styles.container}>
<TextInput ref={'textInput1'} style={styles.textInput} />
<TouchableOpacity onPress={() => this.clearText('textInput1')}>
<Text>Clear text</Text>
</TouchableOpacity>
<TextInput ref={'textInput2'} style={styles.textInput} />
<TouchableOpacity onPress={() => this.clearText('textInput2')}>
<Text>Clear text</Text>
</TouchableOpacity>
</View>
);
}
});
Updated my answer to clear different fields.
You can also use something like this to clear the text of TextInput.
clearText(fieldName) {
this.refs[fieldName].clear(0);
},