Spinner Arc
A rotating arc with a gradient that spins continuously
Last updated on
Manual
Install the following dependencies:
npm install react-native-reanimated react-native-svgCopy and paste the following code into your project.
component/molecules/spinner-arc
import React from "react";import Svg, { Circle, Defs, LinearGradient, Stop } from "react-native-svg";import Animated, { useSharedValue, useAnimatedStyle, withRepeat, withTiming, Easing,} from "react-native-reanimated";import { View, StyleSheet } from "react-native";const AnimatedView = Animated.createAnimatedComponent(View);interface SpinnerArcProps { size?: number; colorStart?: string; colorEnd?: string; strokeWidth?: number; speed?: number; backgroundColor?: string; arcLength?: number;}export const SpinnerArc: React.FC<SpinnerArcProps> = ({ size = 40, colorStart = "#FF4E4E", colorEnd = "#FF7A00", strokeWidth = 4, speed = 1000, backgroundColor = "#ddd", arcLength = 90,}) => { const rotation = useSharedValue(0); // Rotation animation for spinner rotation.value = withRepeat( withTiming(360, { duration: speed, easing: Easing.linear, }), -1, ); const animatedStyle = useAnimatedStyle(() => ({ transform: [{ rotate: `${rotation.value}deg` }], })); return ( <AnimatedView style={[styles.loader, { width: size, height: size }, animatedStyle]} > <Svg width={size} height={size}> <Circle cx={size / 2} cy={size / 2} r={size / 2 - strokeWidth} stroke={backgroundColor} strokeWidth={strokeWidth} fill="none" /> <Defs> <LinearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%"> <Stop offset="0%" stopColor={colorStart} /> <Stop offset="100%" stopColor={colorEnd} /> </LinearGradient> </Defs> <Circle cx={size / 2} cy={size / 2} r={size / 2 - strokeWidth} stroke="url(#gradient)" strokeWidth={strokeWidth} strokeDasharray={arcLength} strokeLinecap="round" fill="none" /> </Svg> </AnimatedView> );};const styles = StyleSheet.create({ loader: { justifyContent: "center", alignItems: "center", },});Usage
import { View, Text, StyleSheet } from "react-native";import { GestureHandlerRootView } from "react-native-gesture-handler";import { StatusBar } from "expo-status-bar";import { useFonts } from "expo-font";import { SymbolView } from "expo-symbols";import { DisclosureGroup } from "@/components/molecules/disclosure-group";import DynamicText from "@/components/molecules/dynamic-text";import { DynamicTextItem } from "@/components/molecules/dynamic-text/types";import GooeyText from "@/components/molecules/gooey-text";import { CircleLoadingIndicator, OrbitDotLoader, PulsingDots, SpinnerArc,} from "@/components";import { CircularLoader } from "@/components/molecules/Loaders/circular";export default function App() { const [fontLoaded] = useFonts({ SfProRounded: require("@/assets/fonts/sf-pro-rounded.ttf"), HelveticaNowDisplay: require("@/assets/fonts/HelveticaNowDisplayMedium.ttf"), }); const OPTIONS = [ { label: "Edit", icon: "pencil" }, { label: "Duplicate", icon: "doc.on.doc" }, { label: "Share", icon: "square.and.arrow.up" }, { label: "Delete", icon: "trash", destructive: true }, ]; const GOOEY_TEXTS: string[] = ["REACTICX", "IS", "AWESOME!"]; return ( <GestureHandlerRootView style={styles.container}> <StatusBar style="light" /> <View style={styles.content}> <SpinnerArc arcLength={270} colorEnd="#6366f1" colorStart="#8b5cf6" backgroundColor="transparent" size={64} speed={500} strokeWidth={3} /> </View> </GestureHandlerRootView> );}const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#0a0a0a", }, content: { paddingHorizontal: 20, paddingTop: 90, justifyContent: "center", alignItems: "center", gap: 0, }, title: { fontSize: 28, fontWeight: "700", color: "#fff", }, subtitle: { fontSize: 15, color: "#555", }, card: { backgroundColor: "#141414", borderRadius: 16, overflow: "hidden", marginTop: 20, }, triggerContent: { padding: 16, }, triggerLeft: { flexDirection: "row", alignItems: "center", gap: 12, }, triggerText: { fontSize: 16, fontWeight: "500", color: "#fff", }, item: { flexDirection: "row", alignItems: "center", gap: 12, padding: 14, backgroundColor: "#1a1a1a", borderRadius: 12, marginBottom: 6, }, itemText: { fontSize: 15, color: "#fff", }, destructiveText: { color: "#ff453a", },});Props
React Native Reanimated
React Native Svg
