🌀 Spinning Wheel Package

A customizable Flutter package for creating visually appealing and interactive spinning wheels — perfect for games, quizzes, random selection tools, and more.

This package supports rich styling, section-specific colors, gradient customization, sound effects, and custom pointer images.


screenshot1 screenshot2 screenshot3

screenshot4 screenshot5

✨ Features

  • 🎨 Customizable spinning wheel
  • 🌈 Gradient color support per section
  • 🔊 Sound playback on spin
  • 🪞 Custom pointer image
  • ⚙️ Silver and Wooden rim styles
  • 🧩 Spin start and result callbacks

🚀 Getting Started

Add the package to your `pubspec.yaml`:

Then, import it:

import 'package:spinning_wheel_package/spinning_wheel_package.dart';

📦 Assets Setup

flutter: assets:

  • assets/audios/spin.mp3
  • assets/images/pointer.png

🎨 Customization Properties

Property Type Description
sections List<WheelItem> Required. The list of items to display on the wheel.
spinDuration double The duration of the spin animation in seconds.
onSpinStart Function()? Callback when the wheel starts spinning — great for playing sound effects.
onSpinEnd Function(int)? Callback when the wheel stops, returning the index of the winning slice.
wheelWidth double The width of the spinning wheel.
wheelHeight double The height of the spinning wheel.
SpinningWheelController SpinningWheelController Programmatically control the wheel from outside the widget.
spinTriggerBuilder Widget Function(void Function() trigger)? Provide a flexible way to create a custom spin trigger widget.
rimType WheelRimType Sets the wheel's rim style: normal, christmas, silver, etc.
wheelRimColor Color The color of the rim when rimType is normal.
wheelRimWidth double The width (thickness) of the wheel's outer rim.
customRimWidth double The width of the image overlay rim (e.g., for silver or wood).
customRimHeight double The height of the image overlay rim.
pegColor Color The color of the pegs between each wheel section.
pegSize double The radius of the pegs.
pegPosition PegPosition Sets the position of the pegs: start or center of each slice.
showChristmasCap bool If true, shows a Santa cap when rimType is christmas.
positionChristmasCapVertical double The vertical position of the Christmas cap overlay.
positionChristmasCapHorizontal double The horizontal position of the Christmas cap overlay.
textOrientation WheelTextOrientation Sets text direction: horizontal or vertical inside each section.
itemTextColor Color The color of the text inside each wheel section.
itemFontSize double The font size for the text in each section.
itemFontWeight FontWeight The font weight for the text in each section.
itemFontFamily String The font family for the text in each section.
textMargin double A multiplier for how far from the center the text is placed (e.g., 0.5).
useCustomPointer bool If true, enables using a custom image for the pointer.
pointerImagePath String? Path to the pointer image asset. Required if useCustomPointer is true.
pointerType PointerType Type of default pointer shape: triangle or cone.
pointerColor Color The color of the default painted pointer.
pointerPinColor Color The color of the small pin on the cone pointer.
positionCustomPointerVertical double The vertical position of the custom image pointer.
positionCustomPointerHorizontal double The horizontal position of the custom image pointer.
positionDefaultPointerVertical double The vertical position of the default painted pointer.
positionDefaultPointerHorizontal double The horizontal position of the default painted pointer.
centerHubWidth double The width of the central hub of the wheel.
centerHubHeight double The height of the central hub of the wheel.
centerHubColor Color The background color of the central hub.
centerHubEdgeColor Color The border color of the central hub.
centerHubText String The text to display inside the central hub.
centerHubTextSize double The font size for the hub text.
centerHubTextColor Color The color for the hub text.
showWheelStand bool If true, displays the stand below the wheel.
standColor Color The color of the wheel stand.
standOffset double Controls the vertical alignment of the stand.
showWheelShadow bool If true, displays a shadow effect around the wheel rim.
wheelShadowColor Color The color of the wheel's outer shadow.

🛠️ Usage Example

import 'package:flutter/material.dart';
import 'package:spinning_wheel_package/spinning_wheel_package.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Spin Package Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(title: 'Wheel Spin Package'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  //final AudioPlayer _audioPlayer = AudioPlayer();
  //bool _isSoundLoading = false;
  String _spinResult = "Spin the wheel!";
  final SpinningWheelController _wheelController = SpinningWheelController();


  final List<WheelItem> _sections = [
    WheelItem(text: "Music", color: Colors.green,),
    WheelItem(text: "Art & Books", color: Colors.orange,),
    WheelItem(text: "Other Sports", color: Colors.purple),
    WheelItem(text: "Nutrition", color: Colors.blue),
    WheelItem(text: "Entertainment", color: Colors.red),
    WheelItem(text: "Current Affairs", color: Colors.yellow),
  ];


  @override
  void dispose() {
    //_audioPlayer.dispose();
    super.dispose();
  }

  //You can define a method to play sound when the wheel is spun
  // Future<void> _playSound() async {
  //   // If a sound is already being prepared, do nothing
  //   if (_isSoundLoading) return;
  //   // Set the flag to block other calls
  //   _isSoundLoading = true;
  //
  //   try {
  //     // setAsset implicitly stops any previous sound
  //     await _audioPlayer.setAsset('assets/audios/spin.mp3');
  //     // Rewind to the beginning to ensure it plays every time
  //     await _audioPlayer.seek(Duration.zero);
  //     _audioPlayer.play();
  //   } catch (e) {
  //     print("Error playing sound: $e");
  //   } finally {
  //     // Always release the flag when done
  //     _isSoundLoading = false;
  //   }
  // }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              _spinResult,
              style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            SpinningWheel(
              sections: _sections,
              controller: _wheelController,
              // spinTriggerBuilder: (trigger) {
              //   return ElevatedButton(
              //     onPressed: () {
              //       // You can add your own logic here before spinning.
              //       print("Custom button tapped!");
              //       ScaffoldMessenger.of(context).showSnackBar(
              //         const SnackBar(content: Text('Spinning with the custom button!')),
              //       );
              //       // Call the provided trigger function to start the spin.
              //       trigger();
              //     },
              //     style: ElevatedButton.styleFrom(
              //       backgroundColor: Colors.teal,
              //       foregroundColor: Colors.white,
              //       padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 15),
              //       textStyle: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
              //     ),
              //     child: const Text('Spin with Builder!'),
              //   );
              // },
              onSpinStart: (){
                //_playSound();
              },
              onSpinEnd: (index) {
                setState(() {
                  _spinResult = "Result: ${_sections[index].text}";
                });
              },
              rimType: WheelRimType.silver,
              standOffset: 0,
              centerHubWidth: 50,
              centerHubHeight: 50,
              centerHubText: 'SPIN',
              useCustomPointer: true,
              pointerImagePath: 'assets/images/pointer.png',
              showWheelStand: true,
              pegPosition: PegPosition.center,
            ),

            const SizedBox(height: 30),
            // This button uses the controller to spin the wheel
            ElevatedButton(
              onPressed: () {
                print("Controller button tapped!");
                _wheelController.spin();
              },
              child: const Text('Spin with Controller'),
            ),

          ],
        ),
      ),
    );
  }
}