👉🏼 React Native InkWell
A material touchable area that provides the ripple effect.
Inspired by the InkWell Flutter component.
Installation
You need to have already installed the following packages:
Open a Terminal in your project's folder and install the library using yarn
:
yarn add react-native-inkwell
or with npm
:
npm install react-native-inkwell
Usage
import InkWell from 'react-native-inkwell';
const YourRippleButton = () => (
<InkWell
style={{
width: 200,
height: 200,
backgroundColor: 'white',
}}
contentContainerStyle={{
alignItems: 'center',
justifyContent: 'center',
}}
onTap={() => {
console.log('tapped');
}}
>
<Text>Tap Here</Text>
</InkWell>
);
Properties
enabled?: boolean
Indicates whether InkWell should be active or not.
Default: true
.
radius?: number
Decides the maximum radius of the Ripple Effect. By default the Ripple effect will determine the radius from the height and width of the component so that it can expand as much as possible.
onTap?: () => void
Called when the InkWell is clicked. If the onDoubleTap callback is not specified, onTap will be called immediately, otherwise it will be called after maxDelayMs.
onTapDown?: () => void
Called when the user taps down the InkWell.
onTapCancel?: () => void
Called when the user cancels a tap.
onDoubleTap?: () => void
Called when the InkWell is clicked two consecutive times in less than maxDelayMs.
onLongPress?: () => void
Called when the component is pressed for more than minDurationMs.
maxDelayMs?: number
Maximum time, expressed in milliseconds, that can pass before the next tap — if many taps are required.
This property is inherited from maxDelayMs of the react-native-gesture-handler's TapGestureHandler.
Default: 500
minDurationMs?: number
Minimum time, expressed in milliseconds, that a finger must remain pressed on the corresponding view.
This property is inherited from minDurationMs of the react-native-gesture-handler's LongPressGestureHandler.
Default: 500
scaleDuration?: number
The duration of ink scale animation.
Default: depends on the component's width and height.
easing?: Animated.WithTimingConfig["easing"]
The Reanimated EasingFunction.
Default: Easing.bezier(0.25, 0.5, 0.4, 1.0)
splashColor?: string
The splash color of the ripple effect.
Default: rgba(0,0,0,0.1)
;
highlightColor?: string
The backgroundColor of the View when the InkWell is activated.
Default: rgba(0,0,0,0.03)
;
style?: StyleProp<ViewStyle>
A React Native style.
contentContainerStyle?: StyleProp<ViewStyle>
The React Native style of the content.
children?: React.ReactNode
The component that could be contained in the InkWell.
simultaneousHandlers and waitFor
Inherited from react-native-gesture-handler in order to support Cross Handler Interactions if needed.
Hooks
useInkWellRef
Under the hood this hook is using useAnimatedRef from react-native-reanimated.
When provided, it is used by the InkWell in order to measure the layout on the UI Thread.
Nested InkWells
Since the InkWell is built on top of the react-native-gesture-handler component TapGestureHandler, by default, upon clicking an InkWell inside another, the tap will be propagated to the parent as well.
Fortunately, this case study is easily handled.
First, a Ref
must be created and assigned to the InkWell
that is being nested. Once this is done, the Ref
must be added to the childrenRefs property of the InkWell
.
That's it.
const NestedInkWellUseCase = () => {
const onTapParent = React.useCallback(() => {
console.log('Parent');
}, []);
const onTapChild = React.useCallback(() => {
console.log('Child');
}, []);
const firstChildRef = useInkWellRef();
const secondChildRef = useInkWellRef();
return (
<View style={styles.buttonContainer}>
{/* Parent */}
<InkWell
style={styles.button}
contentContainerStyle={styles.contentButton}
onTap={onTapParent}
childrenRefs={[firstChildRef, secondChildRef]} // <-- 4. add the childRef to the childrenRefs
>
{/* First nested InkWell */}
<InkWell
ref={firstChildRef} // <-- 2. assign the firstChildRef
style={[styles.button, styles.innerButton]}
contentContainerStyle={styles.contentButton}
onTap={onTapChild}
>
<Text>Child</Text>
</InkWell>
{/* Second nested InkWell */}
<InkWell
ref={secondChildRef} // <-- 3. assign the secondChildRef
style={[styles.button, styles.innerButton]}
contentContainerStyle={styles.contentButton}
onTap={onTapChild}
>
<Text>Child</Text>
</InkWell>
</InkWell>
</View>
);
};
Here's the result:
Contributing
See the contributing guide to learn how to contribute to the repository and the development workflow.
License
MIT