loadable_buttons 1.0.0
loadable_buttons: ^1.0.0 copied to clipboard
Provides enhanced buttons with built-in loading states, async functionality and customizable transitions.
import 'package:flutter/material.dart';
import 'package:loadable_buttons/loadable_buttons.dart';
/// main is the entry point of the application.
void main() {
runApp(const MyApp());
}
/// MyApp is a StatelessWidget. This widget is the root of your application.
class MyApp extends StatefulWidget {
/// Creates a MaterialApp widget.
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late var randomSeedColor = Colors.black;
void _changeSeedColor() {
setState(() {
randomSeedColor = Colors.primaries[
DateTime.now().millisecondsSinceEpoch % Colors.primaries.length];
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.from(
colorScheme: ColorScheme.fromSeed(
seedColor: randomSeedColor,
dynamicSchemeVariant: DynamicSchemeVariant.fidelity,
),
),
home: Builder(builder: (context) {
return DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.primaryContainer,
Theme.of(context).colorScheme.secondaryContainer,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: _HomePage(
onChangeSeedColor: _changeSeedColor,
),
);
}),
);
}
}
/// HomePage is a StatefulWidget that represents the main application page.
class _HomePage extends StatefulWidget {
/// Creates a HomePage widget.
const _HomePage({this.onChangeSeedColor});
final VoidCallback? onChangeSeedColor;
@override
State<_HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<_HomePage> {
TransitionAnimationType transitionType = TransitionAnimationType.stack;
bool _isLongText = false;
static const clickMeText = 'Click me';
static const longClickMeText = 'Click me again';
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
floatingActionButton: Row(
mainAxisSize: MainAxisSize.min,
spacing: 8,
children: [
AsyncFloatingActionButton.extended(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
icon: const Icon(Icons.ads_click_sharp),
label: _isLongText
? const Text(longClickMeText)
: const Text(clickMeText),
),
AsyncFloatingActionButton.extended(
splashFactory: NoSplash.splashFactory,
onPressed: _switchTransitionAnimationType,
label: Text(transitionType.name.capitalize()),
icon: const Icon(Icons.animation),
),
AsyncFloatingActionButton(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
onPressed: () => widget.onChangeSeedColor?.call(),
child: const Icon(Icons.color_lens),
),
],
),
body: Center(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
spacing: 16,
children: [
Text(
"AsyncElevatedButton",
style: TextTheme.of(context).titleLarge,
),
Wrap(
spacing: 8,
runSpacing: 8,
alignment: WrapAlignment.center,
children: [
AsyncElevatedButton(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
child: _isLongText
? const Text(longClickMeText)
: const Text(clickMeText),
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
AsyncElevatedButton.icon(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
label: _isLongText
? const Text(longClickMeText)
: const Text(clickMeText),
icon: const Icon(Icons.add),
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
],
),
Text(
"AsyncFilledButton",
style: TextTheme.of(context).titleLarge,
),
Wrap(
spacing: 8,
runSpacing: 8,
alignment: WrapAlignment.center,
children: [
AsyncFilledButton(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
child: _isLongText
? const Text(longClickMeText)
: const Text(clickMeText),
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
AsyncFilledButton.icon(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
label: _isLongText
? const Text(longClickMeText)
: const Text(clickMeText),
icon: const Icon(Icons.add),
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
AsyncFilledButton.tonal(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
child: _isLongText
? const Text(longClickMeText)
: const Text(clickMeText),
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
AsyncFilledButton.tonalIcon(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
label: _isLongText
? const Text(longClickMeText)
: const Text(clickMeText),
icon: const Icon(Icons.add),
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
],
),
Text(
"AsyncTextButton",
style: TextTheme.of(context).titleLarge,
),
Wrap(
spacing: 8,
runSpacing: 8,
alignment: WrapAlignment.center,
children: [
AsyncTextButton(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
child: _isLongText
? const Text(longClickMeText)
: const Text(clickMeText),
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
AsyncTextButton.icon(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
label: _isLongText
? const Text(longClickMeText)
: const Text(clickMeText),
icon: const Icon(Icons.add),
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
],
),
Text(
"AsyncOutlinedButton",
style: TextTheme.of(context).titleLarge,
),
Wrap(
spacing: 8,
runSpacing: 8,
alignment: WrapAlignment.center,
children: [
AsyncOutlinedButton(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
child: _isLongText
? const Text(longClickMeText)
: const Text(clickMeText),
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
AsyncOutlinedButton.icon(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
label: _isLongText
? const Text(longClickMeText)
: const Text(clickMeText),
icon: const Icon(Icons.add),
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
],
),
Text(
"AsyncIconButton",
style: TextTheme.of(context).titleLarge,
),
Wrap(
spacing: 8,
runSpacing: 8,
alignment: WrapAlignment.center,
children: [
AsyncIconButton(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
icon: const Icon(Icons.flutter_dash),
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
AsyncIconButton.filled(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
iconSize: 32,
icon: const Icon(Icons.flutter_dash),
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
AsyncIconButton.filledTonal(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
icon: const Icon(Icons.flutter_dash),
iconSize: 48,
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
AsyncIconButton.outlined(
splashFactory: NoSplash.splashFactory,
transitionType: transitionType,
icon: const Icon(Icons.flutter_dash),
iconSize: 64,
onPressed: () async {
await Future<void>.delayed(const Duration(seconds: 1));
if (mounted) setState(() => _isLongText = !_isLongText);
},
),
],
),
],
),
),
),
);
}
Future<void> _switchTransitionAnimationType() async {
setState(() {
transitionType = transitionType == TransitionAnimationType.stack
? TransitionAnimationType.animatedSwitcher
: TransitionAnimationType.stack;
});
}
}
/// Extension to capitalize the first letter of a string.
extension StringCapitalization on String {
/// Capitalizes the first letter of the string.
String capitalize() {
if (isEmpty) return this;
return '${this[0].toUpperCase()}${substring(1)}';
}
}