Using RN 0.63.4 and trying to implement a touchable card in Android environment.
The code is pretty simple:
<TouchableOpacity onPress={() => handlePress()}>
<ArticleContainer>
....
</ArticleContainer>
</TouchableOpacity>
This is the CSS for the ArticleContainer
const ArticleContainer = styled.View`
height: 170px;
width: 320px;
border-radius: 11px;
padding: 13px;
margin: 20px 15px 10px 20px;
elevation: 5;
background-color: white;
`;
The UI looks fine when not touched, even the elevation looks pretty good:

But when trying to touch it, it becomes so ugly, look at the weird shadows and border:

Found only a few answers in StackOverflow and one in the official GitHub which both didn't work for me.
Is there is a way to solve that?
I recently faced similar issue. What worked for me was to apply shadows on TouchableOpacity instead of the View inside it.
Not sure about it, but I think that when the shadows were applied on View, the TouchableOpacity will drop the opacity of its child i.e View on being pressed, which somehow did not effect its shadows, leaving them exposed.
That being said I am really not sure about why applying shadows to TouchableOpacity worked.
backgroundColor - In many cases not setting a background color on the component with shadows, causes shadows to not behave properly. Just set it to transparent if you don't want any background color.The solution worked for me but I am not sure if it is the best solution or even if it will work for you as the behavior might be different depending on the platform and also if you are using expo.
I tried to reproduce the issue and apply the solution on expo. Below images shows TouchableOpacity in a pressed state.

I've faced the exact same problem. Just found that it was caused by the elevation in the style. Removed it and solved.
elevation + TouchableOpacity = ugly.
Found a better solution. I use TouchableNativeFeedback for Android, and TouchableOpacity for iOS.
With TouchableNativeFeedback, you need to set background and useForeground props. Note that you also need to set overflow: hidden to the inner view. More details here.
Here's my card view:
interface Props extends TouchableWithoutFeedbackProps {
style?: ViewStyle;
children?: React.ReactNode;
}
export default function CardView({style, children, onPress}: Props) {
const card = (
<View
style={{
shadowColor: 'gery',
backgroundColor: 'white',
padding: 18,
overflow: Platform.OS === 'android' ? 'hidden' : 'visible',
// iOS
shadowOffset: {width: 0, height: 2},
shadowRadius: 18,
shadowOpacity: 0.2,
borderRadius: 12,
// Android
elevation: 8,
...style,
}}>
{children}
</View>
);
if (Platform.OS === 'android') {
return (
<TouchableNativeFeedback
onPress={e => onPress?.call(undefined, e)}
background={TouchableNativeFeedback.Ripple('#00000040', false)}
useForeground={true}>
{card}
</TouchableNativeFeedback>
);
} else {
return (
<TouchableOpacity
onPress={e => onPress?.call(undefined, e)}
activeOpacity={0.5}>
{card}
</TouchableOpacity>
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With