In this lesson, you will learn how to design UI components that provide intuitive, platform-appropriate touch feedback using native ripple effects on Android and opacity adjustments on iOS.
When building cross-platform apps, users expect feedback that matches their specific operating system. On iOS, buttons traditionally provide a subtle "dimming" or opacity change when pressed. On Android, users look for the "ripple" effect—an ink-like animation that originates from the point of contact and spreads across the surface of the component.
To accommodate these different hardware expectations, we use Pressable with a dynamic approach. Instead of forcing one style everywhere, we check the platform and apply the component that offers the native behavior.
Implementing the Pattern
You can use the Platform module to decide which component to render. While Pressable works universally, it requires manual style manipulation to mimic native behavior. For a truly native feel, we ensure our layout handles the ripple overflow correctly:
import { Platform, Pressable, View, StyleSheet } from 'react-native';
const MyButton = ({ children, onPress }) => {
return (
<Pressable
onPress={onPress}
style={({ pressed }) => [
styles.button,
// iOS: Reduce opacity on press
// Android: Handled by system ripple if configured
{ opacity: Platform.OS === 'ios' && pressed ? 0.5 : 1 }
]}
// Android Ripple configuration
android_ripple={{ color: '#ccc', borderless: false }}
>
{children}
</Pressable>
);
};
Designing for Ripple Layouts
When using the android_ripple prop, the effect is physically constrained by the component's boundaries. If your button has rounded corners (using borderRadius), you must ensure your styling handles overflow: 'hidden'. If the overflow isn't hidden, the Android ripple will "bleed" outside the rounded corners, creating an unpolished look that clashes with your carefully designed UI layout. By wrapping your touchable in a View with overflow: 'hidden', you ensure the ripple stays inside your design's intended shape.
This design strategy balances the requirement for a consistent brand identity with the necessity of native platform conventions.
Key Takeaway: Always pair android_ripple with overflow: 'hidden' on your container views to ensure native touch feedback respects your custom border-radius and component boundaries.