Skip to main content

Floating Action Button

Floating Action Button provides user with easy-accessible panel with primary or most common actions on the screen.

Loading...

We use shared values to monitor if the button is expanded. The useSharedValue hook helps prevent unnecessary re-renders during state changes.

  const isExpanded = useSharedValue(false);

const handlePress = () => {
isExpanded.value = !isExpanded.value;

The state is toggled when the main Actions button is pressed, which triggers animations for other secondary buttons.

It also relies on animatable values. Leveraging animatable values of rotation and position enables smooth transition between the two states.

Floating Action Button
  const plusIconStyle = useAnimatedStyle(() => {
const moveValue = interpolate(Number(isExpanded.value), [0, 1], [0, 2]);
const translateValue = withTiming(moveValue);
const rotateValue = isExpanded.value ? '45deg' : '0deg';

return {
transform: [
{ translateX: translateValue },
{ rotate: withTiming(rotateValue) },
],
};
});

The FloatingActionButton is a reusable component that manages button styles, content and animations. For this we use props: buttonLetter, index and isExpanded.

const FloatingActionButton = ({ isExpanded, index, buttonLetter }) => {
const animatedStyles = useAnimatedStyle(() => {
const moveValue = isExpanded.value ? OFFSET * index : 0;
const translateValue = withSpring(-moveValue, SPRING_CONFIG);
const delay = index * 100;

const scaleValue = isExpanded.value ? 1 : 0;

return {
transform: [
{ translateY: translateValue },
{
scale: withDelay(delay, withTiming(scaleValue)),
},
],
};
});

return (
<AnimatedPressable style={[animatedStyles, styles.shadow, styles.button]}>
<Animated.Text style={styles.content}>{buttonLetter}</Animated.Text>
</AnimatedPressable>
);
};

We define the animated styles for the buttons within the FloatingActionButton component, passing the necessary values as props. The delay in their appearance on the screen is calculated based on the button's index. Buttons with a higher index will appear later and be positioned higher in the "column" of buttons.

Floating Action Button
  const animatedStyles = useAnimatedStyle(() => {
const moveValue = isExpanded.value ? OFFSET * index : 0;
const translateValue = withSpring(-moveValue, SPRING_CONFIG);
const delay = index * 100;

const scaleValue = isExpanded.value ? 1 : 0;

return {
transform: [
{ translateY: translateValue },
{
scale: withDelay(delay, withTiming(scaleValue)),
},
],
};
});

return (
<AnimatedPressable style={[animatedStyles, styles.shadow, styles.button]}>
<Animated.Text style={styles.content}>{buttonLetter}</Animated.Text>
</AnimatedPressable>
);
};