🎃

Flutter いいねボタン 簡単連打対応

2023/12/02に公開

はじめに

いいねボタンを実装中に、タップされる度にAPIを叩きたくない。最後のタップの結果だけAPIを叩くよう実装したいと考えた際に実装した方法を記述します。
更に良い方法があれば教えてもらえると嬉しいです🏃

全コード

class LikeButton extends StatefulWidget {
  const LikeButton({Key? key}) : super(key: key);

  @override
  LikeButtonState createState() => LikeButtonState();
}

class LikeButtonState extends State<LikeButton> {
  late bool likeFlg;
  late int likeCount;
  Timer? timer;

  @override
  void initState() {
    /// [likeFlg]と[likeCount]の初期化処理を行う
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        IconButton(
          iconSize: 18.0,
          // いいね済みの場合は赤色のアイコンを表示
          icon: (likeFlg)
              ? const Icon(Icons.favorite, color: Colors.red)
              : const Icon(Icons.favorite_border),
          onPressed: () {
            setState(() {
              // 逆のいいねの状態を取得
              likeFlg = !likeFlg;
              // LikeFlgに応じて、likeCountを調整
              likeFlg ? likeCount += 1 : likeCount -= 1;
            });

            // タイマーが存在していたら、タイマーをキャンセル
            // (前回のタップから0.5秒経過前にタップされた場合は、タイマーをリスタートさせる)
            if (timer != null && timer!.isActive) {
              timer!.cancel();
            }

            timer = Timer(
              // 0.5秒後に処理を行う(タップ後0.5秒経過したら、最後のタップとみなす)
              const Duration(milliseconds: 500),
              () async {
                // likeFlgに変化があった場合のみ、変更処理を行う
                if (likeFlg != initLikeFlg) {
                  // API処理
                }
              },
            );
          },
        ),
        // いいね数
        Text('$likeCount'),
      ],
    );
  }
}

解説

likeFlglikeCountの初期値には、APIレスポンス等の現在の値を追加します。
その後は、UIの変更のために、likeFlglikeCountはローカルの値として、APIは通さず利用します。

タイマー処理

タップ後に、再度タップされずに0.5秒経過したら、処理を行います。

  • timerが初期化されているortimerが起動中に、タップされた場合は、「0.5秒経過していない」とみなせるので、タイマーをキャンセルし、再度0.5秒のタイマーを起動させる。
  • timerが起動後、タップされず0.5秒経過した場合は、「最後のタップ」 とみなし、任意の処理を行います
// タイマーが存在していたら、タイマーをキャンセル
// (前回のタップから0.5秒経過前にタップされた場合は、タイマーをリスタートさせる)
if (timer != null && timer!.isActive) {
 timer!.cancel();
}

timer = Timer(
 // 0.5秒後に処理を行う(タップ後0.5秒経過したら、最後のタップとみなす)
 const Duration(milliseconds: 500),
  () async {
   // likeFlgに変化があった場合のみ、変更処理を行う
   if (likeFlg != initLikeFlg) {
    // API処理
     }
    },
);

Discussion