coverflow_carousel 1.2.1 copy "coverflow_carousel: ^1.2.1" to clipboard
coverflow_carousel: ^1.2.1 copied to clipboard

A highly customizable 3D coverflow-style carousel for Flutter with smooth animations, perspective effects, and controller support.

example/lib/main.dart

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Coverflow Carousel Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        brightness: Brightness.dark,
        primaryColor: Colors.deepPurple,
        scaffoldBackgroundColor: const Color(0xFF0F0E17),
        colorScheme: const ColorScheme.dark(
          primary: Colors.deepPurple,
          secondary: Colors.pinkAccent,
        ),
      ),
      home: const CoverflowDemoScreen(),
    );
  }
}

class CoverflowDemoScreen extends StatefulWidget {
  const CoverflowDemoScreen({super.key});

  @override
  State<CoverflowDemoScreen> createState() => _CoverflowDemoScreenState();
}

class _CoverflowDemoScreenState extends State<CoverflowDemoScreen> {
  final CoverflowCarouselController _controller = CoverflowCarouselController();

  // Carousel Configurations
  bool _isInfinite = true;
  double _obscure = 0.4;
  double _viewportFraction = 0.28;
  CoverflowEntryAnimation _entryAnimation = CoverflowEntryAnimation.stack;
  int _activePage = 0;
  bool _enableHoverTilt = true;
  double _maxHoverTiltAngle = 0.15;

  // Re-keying widget to easily trigger entry animation reload
  Key _carouselKey = UniqueKey();

  // Demo card colors & content
  final List<Map<String, dynamic>> _demoCards = [
    {
      'title': 'Nebula Voyage',
      'subtitle': 'Explore cosmic horizons',
      'colors': [Colors.deepPurple, Colors.pink],
      'icon': Icons.rocket_launch,
    },
    {
      'title': 'Oceanic Abyss',
      'subtitle': 'Deep sea discoveries',
      'colors': [Colors.blue, Colors.cyan],
      'icon': Icons.sailing,
    },
    {
      'title': 'Sunset Dunes',
      'subtitle': 'Warm desert winds',
      'colors': [Colors.orange, Colors.red],
      'icon': Icons.wb_sunny,
    },
    {
      'title': 'Forest Oasis',
      'subtitle': 'Ancient whispering woods',
      'colors': [Colors.teal, Colors.green],
      'icon': Icons.forest,
    },
    {
      'title': 'Aurora Sky',
      'subtitle': 'Northern lights dance',
      'colors': [Colors.purple, Colors.indigo],
      'icon': Icons.ac_unit,
    },
  ];

  void _reloadCarousel() {
    setState(() {
      _carouselKey = UniqueKey();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Coverflow Carousel Demo'),
        centerTitle: true,
        backgroundColor: Colors.transparent,
        elevation: 0,
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.symmetric(vertical: 20),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              // 1. The Coverflow Carousel Container
              SizedBox(
                height: 380,
                child: Center(
                  child: CoverflowCarousel.builder(
                    key: _carouselKey,
                    controller: _controller,
                    itemCount: _demoCards.length,
                    itemWidth: 260,
                    itemHeight: 280,
                    visibleItems: 3,
                    isInfinite: _isInfinite,
                    obscure: _obscure,
                    viewportFraction: _viewportFraction,
                    entryAnimation: _entryAnimation,
                    entryAnimationDuration: const Duration(milliseconds: 1000),
                    entryAnimationCurve: Curves.easeOutBack,
                    enableHoverTilt: _enableHoverTilt,
                    maxHoverTiltAngle: _maxHoverTiltAngle,
                    onPageChanged: (index) {
                      setState(() {
                        _activePage = index;
                      });
                    },
                    centerOverlayBuilder: (context, index) {
                      return Positioned(
                        right: 130 - 28 - 8,
                        bottom: -30,
                        child: Padding(
                          padding: const EdgeInsets.all(16.0),
                          child: Material(
                            color: Colors.pinkAccent,
                            shape: const CircleBorder(),
                            elevation: 8,
                            child: IconButton(
                              icon: const Icon(
                                Icons.play_arrow,
                                color: Colors.white,
                                size: 28,
                              ),
                              onPressed: () {
                                ScaffoldMessenger.of(context).showSnackBar(
                                  SnackBar(
                                    content: Text(
                                      'Playing: ${_demoCards[index]['title']}',
                                    ),
                                    duration: const Duration(seconds: 1),
                                  ),
                                );
                              },
                            ),
                          ),
                        ),
                      );
                    },
                    itemBuilder: (context, index) {
                      final card = _demoCards[index];
                      return Container(
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(24),
                          gradient: LinearGradient(
                            colors: card['colors'] as List<Color>,
                            begin: Alignment.topLeft,
                            end: Alignment.bottomRight,
                          ),
                          boxShadow: [
                            BoxShadow(
                              color: (card['colors'] as List<Color>).first
                                  .withValues(alpha: 0.4),
                              blurRadius: 15,
                              offset: const Offset(0, 8),
                            ),
                          ],
                        ),
                        child: ClipRRect(
                          borderRadius: BorderRadius.circular(24),
                          child: Stack(
                            children: [
                              // Glassmorphic top glow overlay
                              Positioned(
                                top: -50,
                                left: -50,
                                child: Container(
                                  width: 150,
                                  height: 150,
                                  decoration: BoxDecoration(
                                    shape: BoxShape.circle,
                                    color: Colors.white.withValues(alpha: 0.15),
                                  ),
                                ),
                              ),
                              Padding(
                                padding: const EdgeInsets.all(16.0),
                                child: FittedBox(
                                  fit: BoxFit.scaleDown,
                                  alignment: Alignment.bottomLeft,
                                  child: SizedBox(
                                    width:
                                        228, // itemWidth 260 minus horizontal padding 32
                                    child: Column(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      mainAxisAlignment: MainAxisAlignment.end,
                                      children: [
                                        Icon(
                                          card['icon'],
                                          size: 44,
                                          color: Colors.white,
                                        ),
                                        const SizedBox(height: 16),
                                        Text(
                                          card['title'] as String,
                                          style: const TextStyle(
                                            color: Colors.white,
                                            fontSize: 20,
                                            fontWeight: FontWeight.bold,
                                          ),
                                        ),
                                        const SizedBox(height: 6),
                                        Text(
                                          card['subtitle'],
                                          style: TextStyle(
                                            color: Colors.white.withValues(
                                              alpha: 0.8,
                                            ),
                                            fontSize: 13,
                                          ),
                                        ),
                                      ],
                                    ),
                                  ),
                                ),
                              ),
                            ],
                          ),
                        ),
                      );
                    },
                  ),
                ),
              ),

              // Active Page Indicator
              Text(
                'Focused Index: $_activePage',
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.bold,
                  color: Colors.pinkAccent,
                ),
              ),
              const SizedBox(height: 16),

              // 2. Programmatic Controls
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  ElevatedButton.icon(
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.grey[850],
                      foregroundColor: Colors.white,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(12),
                      ),
                      padding: const EdgeInsets.symmetric(
                        horizontal: 16,
                        vertical: 12,
                      ),
                    ),
                    onPressed: () => _controller.previous(),
                    icon: const Icon(Icons.arrow_back),
                    label: const Text('Prev'),
                  ),
                  const SizedBox(width: 20),
                  ElevatedButton.icon(
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.grey[850],
                      foregroundColor: Colors.white,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(12),
                      ),
                      padding: const EdgeInsets.symmetric(
                        horizontal: 16,
                        vertical: 12,
                      ),
                    ),
                    onPressed: () => _controller.next(),
                    icon: const Icon(Icons.arrow_forward),
                    label: const Text('Next'),
                  ),
                ],
              ),
              const SizedBox(height: 30),

              // 3. Configurations Card Panel
              Card(
                margin: const EdgeInsets.symmetric(horizontal: 20),
                color: const Color(0xFF161522),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(20),
                  side: BorderSide(
                    color: Colors.white.withValues(alpha: 0.05),
                  ),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(20),
                  child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      'Interactive Configurations',
                      style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    const Divider(height: 24, color: Colors.grey),

                    // Infinite Scroll Toggle
                    SwitchListTile(
                      title: const Text('Infinite Scroll'),
                      subtitle: const Text('Enable wrap-around page looping'),
                      value: _isInfinite,
                      activeThumbColor: Colors.deepPurpleAccent,
                      onChanged: (val) {
                        setState(() {
                          _isInfinite = val;
                        });
                      },
                    ),

                    // Obscure Blur Slider
                    ListTile(
                      title: const Text('Obscure Blur Intensity'),
                      subtitle: Slider(
                        value: _obscure,
                        min: 0.0,
                        max: 1.0,
                        divisions: 10,
                        activeColor: Colors.deepPurpleAccent,
                        label: _obscure.toStringAsFixed(1),
                        onChanged: (val) {
                          setState(() {
                            _obscure = val;
                          });
                        },
                      ),
                    ),

                    // Viewport Fraction Slider
                    ListTile(
                      title: const Text('Viewport Fraction (Drag Area)'),
                      subtitle: Slider(
                        value: _viewportFraction,
                        min: 0.15,
                        max: 0.45,
                        activeColor: Colors.deepPurpleAccent,
                        label: _viewportFraction.toStringAsFixed(2),
                        onChanged: (val) {
                          setState(() {
                            _viewportFraction = val;
                          });
                        },
                      ),
                    ),

                    // Entry Animation Selection Dropdown
                    ListTile(
                      title: const Text('Entry Animation'),
                      trailing: SizedBox(
                        width: 140,
                        child: DropdownButton<CoverflowEntryAnimation>(
                          isExpanded: true,
                          value: _entryAnimation,
                          underline: const SizedBox(),
                          onChanged: (CoverflowEntryAnimation? newValue) {
                            if (newValue != null) {
                              setState(() {
                                _entryAnimation = newValue;
                              });
                              _reloadCarousel();
                            }
                          },
                          items: CoverflowEntryAnimation.values.map((anim) {
                            return DropdownMenuItem<CoverflowEntryAnimation>(
                              value: anim,
                              child: Text(
                                anim.name,
                                style: const TextStyle(fontSize: 14),
                              ),
                            );
                          }).toList(),
                        ),
                      ),
                    ),

                    // Hover Tilt Toggle
                    SwitchListTile(
                      title: const Text('3D Hover Tilt'),
                      subtitle: const Text('Tilt cards in 3D when hovered by mouse'),
                      value: _enableHoverTilt,
                      activeThumbColor: Colors.deepPurpleAccent,
                      onChanged: (val) {
                        setState(() {
                          _enableHoverTilt = val;
                        });
                      },
                    ),

                    // Hover Tilt Intensity Slider
                    if (_enableHoverTilt)
                      ListTile(
                        title: const Text('Max Tilt Angle (Hover)'),
                        subtitle: Slider(
                          value: _maxHoverTiltAngle,
                          min: 0.05,
                          max: 0.35,
                          activeColor: Colors.deepPurpleAccent,
                          label: '${(_maxHoverTiltAngle * 180 / 3.14159).toStringAsFixed(0)}°',
                          onChanged: (val) {
                            setState(() {
                              _maxHoverTiltAngle = val;
                            });
                          },
                        ),
                      ),

                    const SizedBox(height: 12),
                    Center(
                      child: TextButton.icon(
                        style: TextButton.styleFrom(
                          foregroundColor: Colors.pinkAccent,
                        ),
                        onPressed: _reloadCarousel,
                        icon: const Icon(Icons.refresh),
                        label: const Text('Re-trigger Entry Animation'),
                      ),
                    ),
                  ],
                ),
              ),
            ),
            ],
          ),
        ),
      ),
    );
  }
}
12
likes
0
points
392
downloads

Publisher

verified publishermuditjpalvadi.tech

Weekly Downloads

A highly customizable 3D coverflow-style carousel for Flutter with smooth animations, perspective effects, and controller support.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter

More

Packages that depend on coverflow_carousel