|
import 'package:flutter/material.dart'; |
|
|
|
class AwaitableIconButton extends StatefulWidget { |
|
const AwaitableIconButton({ |
|
Key? key, |
|
required this.onPressed, |
|
required this.icon, |
|
this.indicatorWidget, |
|
this.buttonStyle, |
|
}) : super(key: key); |
|
|
|
/// 押した時の動作 |
|
/// `null` の場合はボタンが非活性になる |
|
final Future<void> Function()? onPressed; |
|
|
|
/// ボタンに表示するラベル文字列 |
|
final Widget icon; |
|
|
|
final Widget? indicatorWidget; |
|
|
|
/// ボタンのスタイル設定。任意設定 |
|
final ButtonStyle? buttonStyle; |
|
|
|
@override |
|
_AwaitableIconButtonState createState() => _AwaitableIconButtonState(); |
|
} |
|
|
|
class _AwaitableIconButtonState extends State<AwaitableIconButton> { |
|
var _isExecuting = false; |
|
|
|
@override |
|
Widget build(BuildContext context) { |
|
return IconButton( |
|
onPressed: widget.onPressed == null ? null : _onPressed, |
|
icon: AnimatedSwitcher( |
|
duration: const Duration(milliseconds: 200), |
|
child: _isExecuting |
|
? widget.indicatorWidget ?? |
|
const CircularProgressIndicator() |
|
: widget.icon, |
|
), |
|
); |
|
} |
|
|
|
Future<void> _onPressed() async { |
|
if (_isExecuting) { |
|
// ボタンアクション実行中は何もしない(連打防止) |
|
return; |
|
} |
|
setState(() => _isExecuting = true); |
|
await widget.onPressed!.call(); |
|
// 画面遷移先から戻ってきた時等のために存在確認してから実行 |
|
if (mounted) { |
|
setState(() => _isExecuting = false); |
|
} |
|
} |
|
} |
|
|
|
void main() => runApp(MyApp()); |
|
|
|
class MyApp extends StatelessWidget { |
|
@override |
|
Widget build(BuildContext context) { |
|
return MaterialApp( |
|
title: 'Flutter Demo', |
|
debugShowCheckedModeBanner: false, |
|
theme: ThemeData( |
|
primarySwatch: Colors.blue, |
|
), |
|
home: const MyHomePage(title: 'Flutter Demo Home Page'), |
|
); |
|
} |
|
} |
|
|
|
class MyHomePage extends StatefulWidget { |
|
final String title; |
|
|
|
const MyHomePage({ |
|
Key? key, |
|
required this.title, |
|
}) : super(key: key); |
|
|
|
@override |
|
_MyHomePageState createState() => _MyHomePageState(); |
|
} |
|
|
|
class _MyHomePageState extends State<MyHomePage> { |
|
|
|
@override |
|
Widget build(BuildContext context) { |
|
return Scaffold( |
|
appBar: AppBar( |
|
title: Text(widget.title), |
|
), |
|
body: Center( |
|
child: AwaitableIconButton( |
|
onPressed: () async { |
|
print('start'); |
|
await Future<void>.delayed(const Duration(seconds: 3)); |
|
print('end'); |
|
}, |
|
icon:const Icon(Icons.send), |
|
), |
|
), |
|
); |
|
} |
|
} |