Flutterでボタンを押したらコールバックを実行している間無効化したい
こんな感じで,ボタンを活性化するかどうかのフラグを渡すコンポーネントがあったとする.
code:dart
class SwitchableFlatButton extends StatelessWidget {
const SwitchableFlatButton({
Key key,
this.buttonText,
this.onTap,
this.enabled,
}) : super(key: key);
final String buttonText;
final VoidCallback onTap;
final bool enabled;
@override
Widget build(BuildContext context) {
return FlatButton(
color: Colors.greenAccent,
textColor: Colors.black87,
disabledColor: Colors.grey,
disabledTextColor: Colors.white,
child: Text(buttonText),
onPressed: enabled ? onTap : null,
);
}
}
このボタンを使って,「ボタンを押したらコールバック実行中は押せないようにしたい」という要件を満たしたい.
例えば
ボタンを押したらAPIコールが走るので,そのレスポンスが返ってくるまで押せないようにしたい
ボタンを押したら他のページに遷移するので,2重に遷移しないようにしたい
要するにボタン連打の対策をしたい.
実装:
code:dart
class _GuardedButton extends StatefulWidget {
const _GuardedButton({Key key, this.buttonText, this.onTap})
: super(key: key);
final String buttonText;
final Function onTap;
@override
__GuardedButtonState createState() => __GuardedButtonState();
}
class __GuardedButtonState extends State<_GuardedButton> {
bool isActive = true;
bool mounted = true;
@override
Widget build(BuildContext context) {
return SwitchableFlatButton(
buttonText: widget.buttonText,
onTap: () async {
setState(() => isActive = false);
await widget.onTap();
if (mounted) setState(() => isActive = true);
},
enabled: isActive,
);
}
@override
void dispose() {
mounted = false;
super.dispose();
}
}
こんな感じのラッパーを用意する.
StatefulもしくはController + Statelessで状態を持てるようにし,ボタンを押したらボタン活性フラグを操作するという流れ.
コールバックが非同期関数のときに対応したいので,ボタンのコールバックはVoidCallbackでなくただのFunctionで受け取る.
あとはこれを使うだけ.
code:dart
class GuardedButtonPage extends StatelessWidget {
const GuardedButtonPage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _GuardedButton(
buttonText: 'TAP ME',
onTap: () async => await Future.delayed(Duration(seconds: 3)),
),
),
);
}
}