Skip to main content

flow_button 1.0.0 copy "flow_button: ^1.0.0" to clipboard
flow_button: ^1.0.0 copied to clipboard

A customizable animated button widget for Flutter with built-in loading, success and error states, smooth transitions, and a tap scale effect.

example/lib/main.dart

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

void main() => runApp(const ExampleApp());

/// Demonstrates the full range of [AnimatedButton] configurations.
class ExampleApp extends StatelessWidget {
  const ExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'flow_button demo',
      theme: ThemeData(
        colorSchemeSeed: Colors.indigo,
        brightness: Brightness.light,
      ),
      darkTheme: ThemeData(
        colorSchemeSeed: Colors.indigo,
        brightness: Brightness.dark,
      ),
      themeMode: ThemeMode.system,
      home: const ExampleHomePage(),
    );
  }
}

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

  @override
  State<ExampleHomePage> createState() => _ExampleHomePageState();
}

class _ExampleHomePageState extends State<ExampleHomePage> {
  late final AnimatedButtonController _controlledController =
      AnimatedButtonController();

  @override
  void dispose() {
    _controlledController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('AnimatedButton Showcase')),
      body: ListView(
        padding: const EdgeInsets.all(24),
        children: [
          const _SectionTitle('Normal'),
          AnimatedButton(onPressed: () {}, child: const Text('Continue')),
          const SizedBox(height: 24),

          const _SectionTitle('Loading (auto, from a Future)'),
          AnimatedButton(
            onPressed: () async {
              await Future.delayed(const Duration(seconds: 2));
            },
            child: const Text('Login'),
          ),
          const SizedBox(height: 24),

          const _SectionTitle('Success'),
          AnimatedButton(
            resetDelay: const Duration(seconds: 2),
            onPressed: () async {
              await Future.delayed(const Duration(seconds: 1));
            },
            child: const Text('Save changes'),
          ),
          const SizedBox(height: 24),

          const _SectionTitle('Error'),
          AnimatedButton(
            resetDelay: const Duration(seconds: 2),
            backgroundColor: Colors.deepOrange,
            onPressed: () async {
              await Future.delayed(const Duration(seconds: 1));
              throw Exception('Network error');
            },
            child: const Text('Submit payment'),
          ),
          const SizedBox(height: 24),

          const _SectionTitle('Disabled'),
          AnimatedButton(
            enabled: false,
            onPressed: () {},
            child: const Text('Unavailable'),
          ),
          const SizedBox(height: 24),

          const _SectionTitle('With icon'),
          AnimatedButton(
            icon: const Icon(Icons.cloud_upload_outlined),
            onPressed: () async {
              await Future.delayed(const Duration(seconds: 1));
            },
            child: const Text('Upload'),
          ),
          const SizedBox(height: 24),

          const _SectionTitle('Custom colors & border'),
          AnimatedButton(
            backgroundColor: Colors.white,
            foregroundColor: Colors.black87,
            border: Border.all(color: Colors.black12, width: 1.5),
            borderRadius: const BorderRadius.all(Radius.circular(8)),
            onPressed: () {},
            child: const Text('Outlined style'),
          ),
          const SizedBox(height: 24),

          const _SectionTitle('Gradient background'),
          AnimatedButton(
            gradient: const LinearGradient(
              colors: [Colors.purple, Colors.pinkAccent],
              begin: Alignment.centerLeft,
              end: Alignment.centerRight,
            ),
            onPressed: () async {
              await Future.delayed(const Duration(seconds: 1));
            },
            child: const Text('Upgrade to Pro'),
          ),
          const SizedBox(height: 24),

          const _SectionTitle('Custom loading indicator'),
          AnimatedButton(
            loadingIndicator: const SizedBox(
              width: 18,
              height: 18,
              child: CircularProgressIndicator(
                strokeWidth: 3,
                color: Colors.amber,
              ),
            ),
            onPressed: () async {
              await Future.delayed(const Duration(seconds: 2));
            },
            child: const Text('Sync now'),
          ),
          const SizedBox(height: 24),

          const _SectionTitle('Controller-driven'),
          Row(
            children: [
              Expanded(
                child: AnimatedButton(
                  controller: _controlledController,
                  onPressed: () {},
                  child: const Text('Controlled'),
                ),
              ),
            ],
          ),
          const SizedBox(height: 8),
          Wrap(
            spacing: 8,
            children: [
              OutlinedButton(
                onPressed: _controlledController.setLoading,
                child: const Text('Set loading'),
              ),
              OutlinedButton(
                onPressed: _controlledController.setSuccess,
                child: const Text('Set success'),
              ),
              OutlinedButton(
                onPressed: _controlledController.setError,
                child: const Text('Set error'),
              ),
              OutlinedButton(
                onPressed: _controlledController.setIdle,
                child: const Text('Reset'),
              ),
            ],
          ),
          const SizedBox(height: 24),

          const _SectionTitle('Sizes'),
          Wrap(
            spacing: 12,
            runSpacing: 12,
            crossAxisAlignment: WrapCrossAlignment.center,
            children: [
              AnimatedButton(
                height: 36,
                onPressed: () {},
                child: const Text('Small'),
              ),
              AnimatedButton(
                height: 48,
                onPressed: () {},
                child: const Text('Medium'),
              ),
              AnimatedButton(
                height: 60,
                onPressed: () {},
                child: const Text('Large'),
              ),
              AnimatedButton(
                width: 240,
                height: 48,
                onPressed: () {},
                child: const Text('Fixed width'),
              ),
            ],
          ),
          const SizedBox(height: 24),
        ],
      ),
    );
  }
}

class _SectionTitle extends StatelessWidget {
  const _SectionTitle(this.title);

  final String title;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 12),
      child: Text(title, style: Theme.of(context).textTheme.titleMedium),
    );
  }
}
2
likes
160
points
363
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A customizable animated button widget for Flutter with built-in loading, success and error states, smooth transitions, and a tap scale effect.

Repository (GitHub)
View/report issues

Topics

#button #animation #widget #ui

License

MIT (license)

Dependencies

flutter

More

Packages that depend on flow_button