async_button_builder
一个构建器,可在执行异步任务的按钮之上添加加载、禁用、出错和完成状态。它可以与几乎任何按钮一起使用,甚至可以与自定义 Material 按钮一起使用。它还通过AnimatedSize结合AnimatedSwitcher来实现状态之间的流畅动画,从而可以定义自己的过渡效果。
入门
包含此包
async_button_builder: <latest_version>
将构建器包装在按钮周围,将 onPressed 和 child 元素直接传递给构建器,而不是按钮本身。这两者是唯一必需的字段。
AsyncButtonBuilder(
child: Text('Click Me'),
onPressed: () async {
await Future.delayed(Duration(seconds: 1));
},
builder: (context, child, callback, _) {
return TextButton(
child: child,
onPressed: callback,
);
},
),

构建器的第四个值允许您监听加载状态。这可用于有条件地设置按钮的样式。此包依赖于freezed,以便创建已密封的联合以更好地处理各种可能的状态。
AsyncButtonBuilder(
child: Text('Click Me'),
loadingWidget: Text('Loading...'),
onPressed: () async {
await Future.delayed(Duration(seconds: 1));
throw 'shucks';
},
builder: (context, child, callback, buttonState) {
final buttonColor = buttonState.when(
idle: () => Colors.yellow[200],
loading: () => Colors.grey,
success: () => Colors.orangeAccent,
error: () => Colors.orange,
);
return OutlinedButton(
child: child,
onPressed: callback,
style: OutlinedButton.styleFrom(
primary: Colors.black,
backgroundColor: buttonColor,
),
);
},
),

您还可以使用buttonState字段自行驱动按钮的状态。
AsyncButtonBuilder(
buttonState: ButtonState.completing(),
// ...
),
async_button_builder甚至适用于自定义按钮。您可以为加载、错误和完成状态定义自己的小部件,以及定义它们之间的过渡。这个例子有点冗长,但展示了其中的一些可能性。
AsyncButtonBuilder(
child: Padding(
// Value keys are important as otherwise our custom transitions
// will have no way to differentiate between children.
key: ValueKey('foo'),
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 8.0,
),
child: Text(
'Click Me',
style: TextStyle(color: Colors.white),
),
),
loadingWidget: Padding(
key: ValueKey('bar'),
padding: const EdgeInsets.all(8.0),
child: SizedBox(
height: 16.0,
width: 16.0,
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
),
),
successWidget: Padding(
key: ValueKey('foobar'),
padding: const EdgeInsets.all(4.0),
child: Icon(
Icons.check,
color: Colors.purpleAccent,
),
),
onPressed: () async {
await Future.delayed(Duration(seconds: 2));
},
loadingSwitchInCurve: Curves.bounceInOut,
loadingTransitionBuilder: (child, animation) {
return SlideTransition(
position: Tween<Offset>(
begin: Offset(0, 1.0),
end: Offset(0, 0),
).animate(animation),
child: child,
);
},
builder: (context, child, callback, state) {
return Material(
color: state.maybeWhen(
success: () => Colors.purple[100],
orElse: () => Colors.blue,
),
// This prevents the loading indicator showing below the
// button
clipBehavior: Clip.hardEdge,
shape: StadiumBorder(),
child: InkWell(
child: child,
onTap: callback,
),
);
},
),
