BoredBurrito
BoredBurrito

Reputation: 121

Style breaks when using TouchableOpacity instead of TouchableWithoutFeedback

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?

Upvotes: 8

Views: 4545

Answers (2)

BoredBurrito
BoredBurrito

Reputation: 121

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>

Upvotes: 2

jevakallio
jevakallio

Reputation: 35890

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.

Upvotes: 11

Related Questions