Floating Action Button
Sleek, animated Floating Action Button
import { StyleSheet, Text, View } from 'react-native'import React from 'react'import Icon from 'react-native-vector-icons/Ionicons'import AnimatedFAB from '../src/components/floatingActionButton'
//or if you're using npm package//import {AnimatedFAB} from '@cascadeui/animated-fab'
const handleClick = () =>{ console.log('navigate') }
const App = () => { return ( <AnimatedFAB menuItems={[ {icon:(<Icon name='aperture' size={32}></Icon>),onPress:handleClick}, {icon:(<Icon name='share' size={32}></Icon>),onPress:handleClick}, {icon:(<Icon name='mic-circle' size={32}></Icon>),onPress:handleClick} ]}/> )}
export default App
const styles = StyleSheet.create({})Installation
- Install component
Terminal window npm install @cascadeui/animated-fab - Add react-native-reanimated plugin into
babel.configmodule.exports = {presets: [... // don't add it here :)],plugins: [...'react-native-reanimated/plugin',],};
-
Install React Native Reanimated
Terminal window npm install react-native-reanimatedTerminal window yarn add react-native-reanimatedTerminal window npx expo install react-native-reanimated -
Add Reanimated plugin into babel.config file
module.exports = {presets: [... // don't add it here :)],plugins: [...'react-native-reanimated/plugin',],}; -
Install
react-native-vector-iconsor@expo/vector-icons(optional)Terminal window npm install react-native-vector-iconsTerminal window yarn add react-native-vector-iconsTerminal window npx expo install react-native-vector-icons -
Edit
android/app/build.gradle(If usingreact-native-vector-icons)apply from: file("../../node_modules/react-native-vector-icons/fonts.gradle") -
Copy core component
src/components/floatingActionButton.tsximport React, { useState } from 'react';import { View, TouchableOpacity, Text, StyleSheet } from 'react-native';import Animated, { useAnimatedStyle, useSharedValue, withTiming, withSpring } from 'react-native-reanimated';import Icon from 'react-native-vector-icons/MaterialIcons';type menuItem = {icon:React.ReactNode,onPress:()=>void}interface FABprop {menuItems : menuItem[]}const AnimatedFAB : React.FC<FABprop> = ({menuItems}) => {const [isOpen, setIsOpen] = useState(false);const rotation = useSharedValue(0);const toggleMenu = () => {setIsOpen((prev) => !prev);rotation.value = withTiming(isOpen ? 0 : 45, { duration: 300 });};const animatedStyle = useAnimatedStyle(() => {const rotate = `${rotation.value}deg`;return {transform: [withSpring({ rotate })],};});// FAB menu item stylesconst animatedMenuStyle = (index: number) =>useAnimatedStyle(() => {const translateY = withTiming(isOpen ? -60 * (index + 1) : 0, { duration: 300 });return {transform: [{ translateY }],};});return (<View style={styles.container}>{/* Menu Items */}{menuItems.map((item,index)=><Animated.View style={[styles.menuItem, animatedMenuStyle(index)]} key={index}><TouchableOpacity style={styles.menuButton} onPress={item.onPress}><Text style={styles.menuText}>{item.icon}</Text></TouchableOpacity></Animated.View>)}{/* Floating Action Button */}<TouchableOpacity style={styles.fab} onPress={toggleMenu} activeOpacity={1}><Animated.View style={animatedStyle}><Icon name="add" size={30} color="white" /></Animated.View></TouchableOpacity></View>);};export default AnimatedFAB;const styles = StyleSheet.create({container: {position: 'absolute',bottom: 50,right: 30,},fab: {width: 60,height: 60,borderRadius: 30,backgroundColor: '#FF6347',justifyContent: 'center',alignItems: 'center',elevation: 5,},menuItem: {position: 'absolute',alignSelf:'center'},menuButton: {width: 50,height: 50,backgroundColor: '#FF6347',justifyContent: 'center',alignItems: 'center',borderRadius: 25,marginBottom: 10,},menuText: {color: 'white',fontWeight: 'bold',},});
Props
| Prop | Type | Description |
|---|---|---|
menuItem | menuItem[] | An array of objects which have info about menu items. |
menuItem
| Prop | Type | Description |
|---|---|---|
icon | ReactElement | Icon or anything you want in the menu item. |
onPress | function | what happens when user click at a particular item. |