state_loading_button 0.1.2 state_loading_button: ^0.1.2 copied to clipboard
一个简单的带进度动画的按钮,可自定义各种状态样式以及动态改变进度动画样式。
import 'dart:async';
import 'package:state_loading_button/state_loading_button.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final ButtonStateNotifier _statusNotifier = ButtonStateNotifier();
final ButtonProgressNotifier _progressNotifier = ButtonProgressNotifier();
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('StateLoadingButton'),
),
body: Center(
child: AnimatedButton(
buttonBuilder: (state) {
switch (state) {
case 'loading':
return ButtonStatus.loading;
case 'normal':
return _normal;
case 'paused':
return _paused;
case 'complete':
return _complete;
case 'error':
return _error;
}
return _normal;
},
progressBuilder: (button, progress) {
switch (button.state) {
case 'normal':
return const ButtonProgress(
size: 13,
dimension: 200,
background: Colors.blue,
foreground: Colors.orangeAccent,
shadows: [BoxShadow(color: Colors.purpleAccent,offset: Offset(0, 4),blurRadius: 5)],
prefix: '前缀',
prefixStyle:
TextStyle(color: Colors.blueGrey, fontSize: 8),
suffix: '后缀',
suffixStyle:
TextStyle(color: Colors.blueAccent, fontSize: 8),
textStyle:
TextStyle(color: Colors.black, fontSize: 10),
progressType:
AnimatedButtonProgressType.linearDeterminate);
case 'paused':
return const ButtonProgress(
prefix: '前缀很长\n',
prefixStyle:
TextStyle(color: Colors.black, fontSize: 8),
suffix: '\n后缀很长',
suffixStyle: TextStyle(
color: Colors.orangeAccent, fontSize: 8),
progressType:
AnimatedButtonProgressType.circularDeterminate,
size: 5,
dimension: 40,
background: Colors.white,
borderSide:
BorderSide(color: Colors.redAccent, width: 5));
case 'complete':
return const ButtonProgress(
progressType:
AnimatedButtonProgressType.linearIndeterminate,
shadows: [BoxShadow(color: Colors.black,offset: Offset(0, 2),blurRadius: 5)],
size: 10,
dimension: 200);
case 'error':
return const ButtonProgress(
progressType:
AnimatedButtonProgressType.circularIndeterminate,
shadows: [BoxShadow(color: Colors.yellow,offset: Offset(0, 2),blurRadius: 5)],
size: 5,
dimension: 30);
default:
return progress;
}
},
stateNotifier: _statusNotifier,
buttonProgressNotifier: _progressNotifier,
onTap: (button) {
switch (button.state) {
case 'normal':
_statusNotifier.value='loading';
int progress = 0;
Timer.periodic(const Duration(milliseconds: 30), (timer) {
progress++;
_progressNotifier.changeProgress(
progress: progress,
foreground: Color.lerp(
Colors.white, Colors.red, progress / 100),
background: Color.lerp(
Colors.green, Colors.yellow, progress / 100));
if (progress > 100) {
_statusNotifier.value='paused';
timer.cancel();
}
});
break;
case 'paused':
_statusNotifier.value='loading';
int progress = 0;
Timer.periodic(const Duration(milliseconds: 30), (timer) {
_progressNotifier.changeProgress(
progress: progress,
foreground: Color.lerp(
Colors.yellow, Colors.white, progress / 100),
background: Color.lerp(
Colors.redAccent, Colors.blue, progress / 100),
circularBackground: Color.lerp(Colors.pink, Colors.purple, progress / 100)
);
progress++;
if (progress > 100) {
_statusNotifier.value='error';
timer.cancel();
}
});
break;
case 'complete':
_statusNotifier.value='loading';
Future.delayed(const Duration(milliseconds: 3000), () {
_statusNotifier.value='normal';
});
break;
case 'error':
_statusNotifier.value='loading';
Future.delayed(const Duration(milliseconds: 3000), () {
_statusNotifier.value='complete';
});
break;
}
},
),
),
),
);
}
///默认
static const ButtonStatus _normal = ButtonStatus(
state: 'normal',
status: AnimatedButtonStatus.button,
text: 'click loading',
textStyle: TextStyle(fontSize: 14.0, color: Colors.white),
buttonColor: Colors.blue,
borderRadius: BorderRadius.all(Radius.circular(30)),
shadows: [BoxShadow(
color: Colors.redAccent,
offset: Offset(0, 5),
blurRadius: 15
)]
);
///暂停
static const ButtonStatus _paused = ButtonStatus(
width: 200,
state: 'paused',
status: AnimatedButtonStatus.button,
text: 'Paused',
textStyle: TextStyle(fontSize: 14.0, color: Colors.white),
buttonColor: Colors.orangeAccent,
borderRadius: BorderRadius.all(Radius.circular(12)),
shadows: [BoxShadow(
color: Colors.blue,
blurRadius: 8
)]
);
///取消
static const ButtonStatus _canceled = ButtonStatus(
state: 'canceled',
status: AnimatedButtonStatus.button,
text: 'Canceled',
textStyle: TextStyle(fontSize: 14.0, color: Colors.white),
buttonColor: Colors.grey,
borderRadius: BorderRadius.all(Radius.circular(12)),
);
///完成
static const ButtonStatus _complete = ButtonStatus(
width: 80,
height: 40,
borderSide: BorderSide(color: Colors.black, width: 3),
state: 'complete',
status: AnimatedButtonStatus.button,
text: 'Complete',
textStyle: TextStyle(fontSize: 14.0, color: Colors.white),
buttonColor: Colors.greenAccent,
borderRadius: BorderRadius.all(Radius.circular(12)),
);
///错误
static const ButtonStatus _error = ButtonStatus(
height: 50,
borderSide: BorderSide(color: Colors.blue, width: 3),
state: 'error',
status: AnimatedButtonStatus.button,
text: 'Error',
textStyle: TextStyle(fontSize: 14.0, color: Colors.white),
buttonColor: Colors.redAccent,
borderRadius: BorderRadius.all(Radius.circular(12)),
);
}