1

Import Required Libraries

💡 Tip: Use the button on the right side to easily copy the code.

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

2

Define the Main Widget

Define the SpinAndWin widget as a StatefulWidget, which will display the spin wheel and handle interactions.

💡 Tip: Use the button on the right side to easily copy the code.

class SpinAndWin extends StatefulWidget {
    const SpinAndWin({Key? key}) : super(key: key);
    
    @override
    State<SpinAndWin> createState() => _SpinAndWinState();
    }
3

Initialize State and Animation Controller

Create the state class _SpinAndWinState and initialize an animation controller, which will manage the spinning effect.

💡 Tip: Use the button on the right side to easily copy the code.

class _SpinAndWinState extends State<SpinAndWin> with SingleTickerProviderStateMixin {
    late AnimationController _controller;
    late Animation<double> _animation;
    final Random _random = Random();
    int _totalPoints = 0;
    int _currentPoints = 0;
    bool _isSpinning = false;
                              
                              
4

Define the Wheel Segments and Initialize Animation Controller

Define the segments of the wheel, each with a color and points. Also, set up the animation controller and handle the end of the spin.

💡 Tip: Use the button on the right side to easily copy the code.

final List<Map<String, dynamic>> segments = [
{'points': 10, 'color': Colors.red},
{'points': 20, 'color': Colors.orange},
// Add remaining segments here
];

@override
void initState() {
super.initState();
_controller = AnimationController(
    vsync: this,
    duration: const Duration(seconds: 5),
);

_controller.addStatusListener((status) {
    if (status == AnimationStatus.completed) {
    setState(() {
        _isSpinning = false;
        _calculatePoints();
    });
    }
});
}
5

Implement Points Calculation

Write a function _calculatePoints() to determine how many points the user wins based on where the wheel stops.

💡 Tip: Use the button on the right side to easily copy the code.

void _calculatePoints() {
    final double finalAngle = _animation.value % (2 * pi);
    final double normalizedAngle = finalAngle >= 0 ? finalAngle : (2 * pi + finalAngle);
    final int segmentIndex = (normalizedAngle / (2 * pi) * segments.length).floor() % segments.length;
    final int wonPoints = segments[segmentIndex]['points'] as int;

    setState(() {
        _currentPoints = wonPoints;
        _totalPoints += wonPoints;
    });

    _showWinDialog(wonPoints);
    }
6

Display Win Dialog

Create a _showWinDialog() function to show an alert dialog when the user wins points.

💡 Tip: Use the button on the right side to easily copy the code.

void _showWinDialog(int points) {
    showDialog(
        context: context,
        builder: (BuildContext context) {
        return AlertDialog(
            title: const Text('🎉 Congratulations! 🎉'),
            content: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
                Text('You won $points points!', style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
                const SizedBox(height: 10),
                Text('Total Points: $_totalPoints'),
            ],
            ),
            actions: [
            TextButton(
                child: const Text('Spin Again'),
                onPressed: () {
                Navigator.of(context).pop();
                },
            ),
            ],
        );
        },
    );
    }


7

Create the Spin Function

Define _spinWheel() to initiate the spinning, setting the animation to rotate by a random number of spins.

💡 Tip: Use the button on the right side to easily copy the code.

void _spinWheel() {
    if (_isSpinning) return;

    setState(() {
        _isSpinning = true;
        _currentPoints = 0;
    });

    final double spins = 3 + _random.nextDouble() * 2;
    final double angle = spins * 2 * pi;

    _animation = Tween<double>(begin: 0, end: angle).animate(
        CurvedAnimation(parent: _controller, curve: Curves.easeOutCirc),
    );

    _controller.reset();
    _controller.forward();
    }
8

Build the UI and Main Function

Build the Scaffold widget UI for the spin wheel and add the WheelPainter class to paint each segment.

💡 Tip: Use the button on the right side to easily copy the code.


@override
Widget build(BuildContext context) {
    return Scaffold(
    body: Container(
        width: double.infinity,
        height: double.infinity,
        decoration: BoxDecoration(
        gradient: LinearGradient(begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Colors.blue.shade900, Colors.blue.shade600]),
        ),
        child: SafeArea(
        child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
            const Text('Spin To Win Daily Earn', style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold, color: Colors.yellow)),
            const SizedBox(height: 20),
            Stack(alignment: Alignment.center, children: [
                AnimatedBuilder(
                animation: _controller,
                builder: (_, child) {
                    return Transform.rotate(
                    angle: _controller.isAnimating ? _animation.value : 0,
                    child: Container(width: 300, height: 300, decoration: const BoxDecoration(shape: BoxShape.circle), child: CustomPaint(painter: WheelPainter(segments: segments))),
                    );
                },
                ),
                Container(width: 20, height: 20, decoration: const BoxDecoration(color: Colors.white, shape: BoxShape.circle)),
            ]),
            const SizedBox(height: 40),
            ElevatedButton(
                onPressed: _isSpinning ? null : _spinWheel,
                style: ElevatedButton.styleFrom(backgroundColor: Colors.redAccent, padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 15), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25))),
                child: Text(_isSpinning ? 'Spinning...' : 'SPIN!', style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
            ),
            const SizedBox(height: 20),
            Text('Total Points: $_totalPoints', style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.yellow)),
            ],
        ),
        ),
    ),
    );
}
}

class WheelPainter extends CustomPainter {
final List<Map<String, dynamic>> segments;

WheelPainter({required this.segments});

@override
void paint(Canvas canvas, Size size) {
    final double radius = size.width / 2;
    final Offset center = Offset(radius, radius);
    final double segmentAngle = 2 * pi / segments.length;

    for (int i = 0; i < segments.length; i++) {
    final Paint paint = Paint()..color = segments[i]['color'];
    final Path path = Path()..moveTo(center.dx, center.dy)..arcTo(Rect.fromCircle(center: center, radius: radius), i * segmentAngle, segmentAngle, true)..close();
    canvas.drawPath(path, paint);

    final double textAngle = i * segmentAngle + segmentAngle / 2;
    final double textRadius = radius * 0.7;
    final Offset textCenter = Offset(center.dx + textRadius * cos(textAngle), center.dy + textRadius * sin(textAngle));

    final TextPainter textPainter = TextPainter(text: TextSpan(text: '${segments[i]['points']}', style: const TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold)), textDirection: TextDirection.ltr)..layout();
    textPainter.paint(canvas, textCenter.translate(-textPainter.width / 2, -textPainter.height / 2));
    }
}

@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

void main() {
runApp(const MaterialApp(home: SpinAndWin()));
}
                                               
 
Step 1 of 8