Style breaks when using TouchableOpacity instead of TouchableWithoutFeedback - react-native

Here's how this part looks using TouchableWithoutFeedback
And here is the same thing, except with TouchableOpacity
The code for this part:
<TouchableWithoutFeedback>
<View style={styles.buyCoinsItem}>
<View style={styles.cost}>
<Text>{no_of_coins}</Text>
</View>
<Text>{product.priceString}</Text>
<View style={{height:30, flexDirection: 'row', marginTop:10}}>
{displayDiscount &&
<View style={styles.discountContainer}>
<Text style={styles.whiteText}>Save {discount}</Text>
</View>
}
</View>
</View>
</TouchableWithoutFeedback>
What's going on here?

This is an annoying side effect of how the two components are implemented.
Essentially, TouchableOpacity is a native-backed View that supports touch interactions by calling setNativeProps({ opacity }) on that view, whereas TouchableWithoutFeedback is simply wraps a native view and attaches the touch handlers.
In order to make TouchableWithoutFeedback behave like TouchableOpacity, nest an additional View inside it, and define any styles on the child view:
Before:
<TouchableOpacity onPress={...} style={styles.touchable}>
// Touchable content
</TouchableOpacity>
After:
<TouchableWithoutFeedback onPress={...}>
<View style={styles.touchable}>
// Touchable content
</View>
</TouchableWithoutFeedback>
I'm not sure why the API was designed this way - my guess would be to avoid creating an additional native backing view for performance reasons when it's not needed.
However, from refactoring purposes, this makes it slightly more painful to move between different types of Touchables. In my projects, I typically create a custom Touchable component that wraps this logic behind a prop, or use something like react-native-platform-touchable, which gives you Android Material-style effects on Android.

Nvm, I figured it out. I basically switched the TouchableOpacity with the outer View. So, like this:
<View style={styles.buyCoinsItem}>
<TouchableOpacity>
<View style={styles.cost}>
<Text>{no_of_coins}</Text>
</View>
<Text>{product.priceString}</Text>
<View style={{height:30, flexDirection: 'row', marginTop:10}}>
{displayDiscount &&
<View style={styles.discountContainer}>
<Text style={styles.whiteText}>Save {discount}</Text>
</View>
}
</View>
</TouchableOpacity>
</View>

Related

Keyboard and layout handling with React Native

I've been trying to figure out how to properly handle layout changes after keyboard opens up (At least on Android). I'm using latest Expo.
Example of my form:
<View style={{flex: 1}}>
<View style={{flex: 1}}></View>
<View style={{flex: 2}}>
<TextInput></TextInput>
<TextInput></TextInput>
<TextInput></TextInput>
<TextInput></TextInput>
<Button></Button>
</View>
</View>
The problem is, when i click on any TextInput, the keyboard squishes everything thats above it and it becomes unreachable until i close the keyboard.I've already tried using:
KeyboardAvoidingView + ScrollView inside
"softwareKeyboardLayoutMode": "pan" in app.json
KeyboardAwareScrollView - seems to be working, kinda, problem below
I also have a problem with "pan" setting, screen adjusts weirdly in a way that it will squish top elements when i click on a bottom TextInput, but wont when i click on a top TextInput, which breaks KeyboardAwareScrollView i guess (It adds different padding/height to the bottom of a screen depending on where i click to open a keyboard)
Does anybody have a better solution to this problem? I want it to simply enable scroll on view (add height ?) without squishing flexboxes or changing anything in my layout.
It's really tough to manage multiple inputs with help of the keyboard avoiding view from React Native Library.
To find the workaround for this, and fix the issues with the Multiple Inputs and Keyboard management in iOS, I have used an npm dependency known as react-native-keyboard-aware-scrollview
Which really helped me in achieving my goal.
You can also try the npm dependency, I hope it will surely help you in achieving your desired outcome.
Here I am attaching the HOC component, Using which I wrap my components in which I need to manage the input and keyboard avoiding.
HOC Component :
import * as React from "react"
import { View, TouchableWithoutFeedback, Keyboard } from "react-native"
import SafeAreaView from 'react-native-safe-area-view'
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view"
/**
* Root component for screen managing safe area view and keyboard avoiding view
*/
const Root = (props) => {
const { style, children } = props
return (
<SafeAreaView style={{ flex: 1, backgroundColor: 'white' }}>
<KeyboardAwareScrollView
keyboardShouldPersistTaps={'always'}
contentContainerStyle={{
flexGrow: 1 // this will fix scrollview scroll issue by passing parent view width and height to it
}}
>
<TouchableWithoutFeedback
onPress={Keyboard.dismiss}
style={{ flexGrow: 1 }}
>
<View style={{ flexGrow: 1 }}>
{children}
</View>
</TouchableWithoutFeedback>
</KeyboardAwareScrollView>
</SafeAreaView>
)
}
export default Root
Simply wrap it with ScrollView, as seen below.
<ScrollView>
<View style={{flex: 1}}>
<View style={{flex: 1}}></View>
<View style={{flex: 2}}>
<TextInput></TextInput>
<TextInput></TextInput>
<TextInput></TextInput>
<TextInput></TextInput>
<Button></Button>
</View>
</View>
</ScrollView>

ScrollView not working even tho it works on other components

Hello guys i have been working on the ubereats clone and while using scrollView it doesnt work ,
i used it on other components the same way and it worked fine but here it doesnt !! ?
const MenuItem=()=>{
return(
<ScrollView showsVerticalScrollIndicator={false}>
<View style={{paddingHorizontal:10}} >
{Menu.map((food,index)=>(
<View style={{paddingLeft:20,flexDirection:"row",marginTop:30,borderTopWidth:1,borderTopColor:"lightgray",paddingTop:10}} key={index} >
<View style={{justifyContent:"center"}}><BouncyCheckbox
iconStyle={{borderColor: "gray",borderRadius:0}}
fillColor='green'
/></View>
<View style={{width:220,marginLeft:10}}>
<Text style={{fontSize:20,fontWeight:"700"}}>{food.title}</Text>
<Text > {food.description}</Text>
<View style={{marginTop:8}}>
<Text style={{fontSize:17,fontWeight:"500"}}>{food.price}</Text></View>
</View>
<View style={{marginLeft:18}}>
<Image source={{uri:food.image}} style={{width:80,height:80,borderRadius:30}}/>
</View>
</View>
))}
</View>
</ScrollView>
)
}```
i used flex 1 on the view outside the map function and it didnt fix it
Remove the View above the ScrollView.
You try to set one child for the scrollView it’s the View component and the View component have array map.
Remove the View component to keep array map child for ScrollView

TouchableHighlight not working although using the source code from official react native documentation

I'm a new react native developer and I have an issue with TouchableHighlight where it always shows an error "Error: React.Children.only expected to receive a single React element child." in addition while I remove it is work as usual and I assume if this issue come from my device/vscode/browser. Because I already follow the source code from https://reactnative.dev/docs/touchablehighlight but still show that error.
Error image
Image without TouchableHighlight tag
Here my code
render() {
return (
<View style={styles.container}>
<TouchableHighlight onPress={this.onPress}>
<View style={styles.button}>
<Text>Touch Here</Text>
</View>
</TouchableHighlight>
<View style={[styles.countContainer]}>
<Text style={[styles.countText]}>
{this.state.count ? this.state.count : null}
</Text>
</View>
</View>
);}
From the error message, the issue might happen if you pass Mutlipe child components to TouchableHighlight
From the docs:
TouchableHighlight must have one child (not zero or more than one). If you wish to have several child components, wrap them in a View
<TouchableHighlight onPress={onPress}>
<View style={styles.button}> // Mutlipe child components are wrapped in a View
<Text>Touch</Text> // component 1
<Text>Here</Text> // component 2
</View>
</TouchableHighlight>

React Native: View onPress does not work

I'm facing a weird problem. In my react native app, if I set onPress event to View it is not triggered but if I set the same to Text inside View, it fires. What am I missing here?
<View style={{backgroundColor: "red", padding: 20}}>
<Text onPress={()=> {
console.log('works');
}
}>X</Text>
</View>
<View style={{backgroundColor: "red", padding: 20}} onPress={()=> {
console.log('does not work');
}
}>
<Text>X</Text>
</View>
Why is this so? Is this an issue with React Native? I'm using version 0.43
You can use TouchableOpacity for onPress event.
View doesn't provide onPress prop.
<TouchableOpacity style={{backgroundColor: "red", padding: 20}} onPress={()=> {
console.log('does not work');
}
}>
<Text>X</Text>
</TouchableOpacity>
You can wrap the view with a TouchableWithoutFeedback and then use onPress and friends like usual. Also you can still block pointerEvents by setting the attribute on on the child view, it even blocks pointer events on the parent TouchableWithoutFeedback, its interesting, this was my need on Android, I didn't test on iOS:
https://facebook.github.io/react-native/docs/touchablewithoutfeedback.html
<TouchableWithoutFeedback onPressIn={this.closeDrawer}>
<Animated.View style={[styles.drawerBackground, styleBackground]} pointerEvents={isOpen ? undefined : 'none'} />
</TouchableWithoutFeedback>
Alternatively you can also provide onStartShouldSetResponder to your view, like so:
<View onStartShouldSetResponder={() => console.log("View click")}>
// some code here
</View>
You can use TouchableOpacity, TouchableHighlight, TouchableNativeFeedback, to achieve this. View component doesn't provide onPress as props. So you use these instead of that.
<TouchableNativeFeedback
onPress={this._onPressButton}
</TouchableNativeFeedback>
OR
<TouchableHighlight onPress={this._onPressButton}>
</TouchableHighlight>
OR
<TouchableOpacity onPress={this._onPressButton}>
</TouchableOpacity>
onPress doesn't work on <View> tag use <TouchableOpacity> instead of View
<View>
<TouchableOpacity onPress={() => 'call your function here'}>
</TouchableOpacity>
</View>
For this issue you can make use either
touchable(opacity,withoutfeedback,....)
or Pressable component which is currently available in react native Package like,
<TouchableOpacity onPress={()=>console.log("Pressed")}>
....
</TouchableOpacity>
or
<Pressable onPress={()=>console.log("Pressed")}>
....
</Pressable>
2021
If you're looking for a more extensive and future-proof way to handle touch-based input, check out the Pressable API.
Source: https://reactnative.dev/docs/touchablewithoutfeedback
A new pressable component is provided in 0.67 of react native, which can solve your problem. It runs anywhere
enter image description here
well we can make the View have a onPress props onStartShouldSetResponder and onResponderGrant
<View
onStartShouldSetResponder={() => true}
onResponderGrant={() => console.log("view pressed")}
>
</View>
You can use TouchableOpacity for that purpose
<TouchableOpacity onPress={() => {your code here}}>
//Your inner views here
</TouchableOpacity>
In View onPress will not work because onPress event is not supported in view tag.That is why it is not working but you can go to this link https://reactnative.dev/docs/view
You can use Pressable components which is react native core component and wrap your View or any other component in Pressable which don't have onPress prop.
Like this:
<Pressable onPress={()=>console.log('pressed')}>
<View>
<Text>Some Text</Text>
</View>
</Pressable>
Pressable Documentation
For anybody who's lookig for a solution to this, as of RN 0.63, there is a new Pressabe api. It might have rolled out a couple versions earlier but it works great for such use cases.
<Pressable onPress={onPressFunction}>
<Text onPress={() => {
console.log('works');
}}>X</Text>
</Pressable>

React Native detect tap on View

I’m writing a React Native app and I want to detect tap/clicks anywhere on the screen so I put an onClick handler on my <View> element but it doesn’t seem to be working. Here is my render function:
<View style={styles.container} onClick={this.onClick}>
<Text style={styles.welcome}>
Tap to change the background
</Text>
</View>
What do I need to do?
For making any element to handle touch/click events in a React-Native UI, you need to put the element inside a TouchableOpacity, TouchableWithoutFeedback, TouchableNativeFeedback or TouchableHighlight element:
<TouchableHighlight onPress = { this.onClick }>
<View style={styles.container}>
<Text style={styles.welcome}>
Tap to change the background
</Text>
</View>
</TouchableHighlight>
Hope that helps.
In React Native version > 55.3 you make check onPress events into your View if use onStartShouldSetResponder props.
Like example:
<View
style={{ flex: 1 }}
onStartShouldSetResponder={() => console.log('You click by View')}
>
<ScrollView
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this.onRefresh} />
}
>
<Text>Awesome</Text>
</ScrollView>
</View>
In example I showed how you can get onPress event on View and not blocking other event behind them. Refresh control still work correct.
In my case the following works fine. You can use onTouchStart and onTouchEnd handlers on any View via props, for example:
<View onTouchStart={() => this.doSomething()} />
More information
This worked for me...
onTouchEnd={() => alert('TAPPED')}
The easiest way to do that:
<TouchableOpacity style={styles.container} onPress={()=> whateverFunc(parameter)}>
<Text style={styles.welcome}>
Tap to change the background
</Text>
</TouchableOpacity>
So, you need to replace the 'View' component to a 'TouchableOpacity' or any other Touchable component and you also need to replace the 'onClick' prop to 'onPress'. That's all. The wrapping of a view with a TouchableWhatever component is not necessary at all.