※本記事は2021年8月31日に更新しました。
「ボタンを長押しの間カウントアップし続ける機能ってどう書けばいいの?」
本記事はそんな疑問にお答えします。
まずはこちらの動画をご覧ください。
外見はFlutterでプロジェクトを立ち上げた際のアプリと同じですが、
ボタンに長押し機能が追加されていることがわかります。
今回は、このようなボタンを長押しの間カウントアップする機能の追加の仕方を解説します。
前提として開発環境はFlutter 2.2.3となります。
それでは参りましょう!
解説
概要
ボタン長押しの間カウントアップさせる機能の実装について、概要を説明します。
GestureDetecterのonLongPressで長押しを検知し、カウントアップの無限ループを発生させ、
onLongPressEndで長押し終了を検知し、無限ループを止める、というのが考え方です。
実装手順は以下の通りです。
- 長押しされているかを判別するフラグを用意
- 長押ししたいwidget(ボタンなど)をGestureDetectorでラップ
- onLongPressにasyncな関数を用意
- 3.の関数内でフラグをtrueにし、フラグを条件に持つwhile文を用意
- while文内でsetState、カウントアップ処理を記載
- while文内にFuture.delayedを設定
- onLongPressEnd に関数を用意し、フラグをfalseにする処理を記載
一つ一つ解説していきます。
長押しされているかを判別するフラグを用意
長押しされているかを判別するフラグとして、bool 型の変数をStatefulWidgetのState内に定義します。
このフラグがtrueの時ループ処理を行うようにし、
onLongPressEndでfalseにすることでループ処理が止まります。
長押ししたいwidget(ボタンなど)をGestureDetectorでラップ
長押しの対象となるwidget(ボタンなど)をGestureDetectorでラップします。
GestureDetector(
child: widget
onLongPress : (){}
onLongPressEnd : (detail){}
)
GestureDetector はタップや長押しなど様々なユーザーの動作に対する処理を記載することができます。
今回は長押しされたことを検知するonLongPress,長押しの終了を検知するonLongPressEndを使用します。
onLongPressにasyncな関数を用意
onLongPressにasyncな関数を用意します。
onLongPress : () async{}
なぜasyncなのかというと、この後に非同期処理のFuture.delayedを用いる為です。
関数内でフラグをtrueにし、フラグを条件に持つwhile文を用意
onLongPressの関数内でフラグをtrueにし、フラグを条件に持つwhile文を用意します。
onLongPress : () async{
_longPressFlag = true;
while(_longPressFlag){
// ・・・
}
}
これで、長押しが開始と同時に無限ループが発生するようになります。
while文内でsetState、カウントアップ処理を記載
while文内でsetState、カウントアップ処理を記載します。
while(_longPressFlag){
setState(() {
_counter++;
});
}
setStateを何回も繰り返すことで、カウントアップを何度も画面表示させることができます
while文内にFuture.delayedを設定
while文内にFuture.delayedを設定します。
while(_longPressFlag){
setState(() {
_counter++;
});
await Future.delayed(Duration(milliseconds: 100));
}
今回のカウントアップ処理のポイントとなります。
この処理なしで実装するとカウントアップが速すぎて画面上で確認できません。
0.1 秒の待機時間を持たせることで、一つ一つカウントが上がっていくことを
確認できるようになります。
onLongPressEnd に関数を用意し、フラグをfalseにする処理を記載
onLongPressEnd に関数を用意し、フラグをfalseにする処理を記載します。
onLongPressEnd: (detail) {
setState((){
_longPressFlag = false;
});
},
この処理が今回一番重要となります。
onLongPressEndに記載の処理は長押しの終了と同時に実行されます。
この処理でフラグをfalseにすることで、長押しの実行時に開始した無限ループを
止めることができます。
長押しの実行 → 無限ループ開始
長押しの終了 → 無限ループ終了
とすることで、長押ししている間処理を行わせることができるわけです。
以上が、ボタン長押しでカウントアップする方法の解説となります。
サンプルコード
最後にサンプルコードを記載します。
ポイントにはコメントを記載しているので、参考にしてください。
main.dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Long Press Button Sample'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
//長押しされているかどうかの判定フラグ
bool _longPressFlag = false;
//ボタンの色を保存する変数
Color? _longPressColor = Colors.blue;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: GestureDetector(
child: FloatingActionButton(
onPressed: _incrementCounter,
// tooltip とは競合するためコメントアウト
// tooltip: 'Increment',
backgroundColor: _longPressColor,
child: Icon(Icons.add),
),
//長押しを検知した際に呼ばれるメソッドを定義
//delayedを使うため、async
onLongPress: () async {
//長押しされているかどうかを判別するフラグをtrueに
_longPressFlag = true;
//ボタンの色を変更
_longPressColor = Colors.green;
//FlagがTrueの間、setStateし続ける
while (_longPressFlag) {
setState(() {
_counter++;
});
//目で追える速さで進行させる為待機処理を追加する
await Future.delayed(Duration(milliseconds: 100));
}
},
//指が離れた際呼び出されるメソッド
onLongPressEnd: (detail) {
setState((){
//Flagをfalseにし、上の反復処理を止める
_longPressFlag = false;
//色を元に戻す
_longPressColor = Colors.blue;
});
},
),
);
}
}
まとめ
今回はボタン長押しでカウントアップする方法について解説しました。
カウンターアプリではよく使う機能となるかと思います。
実装もそこまで難しくないので、ぜひ使ってみてください。
本記事が参考になれば幸いです。
コメント