🐀

FlutterのCallBackとは?

2023/03/16に公開

Overview

コールバックというのは、コールバック関数と呼ばれている関数を引数として、関数で使うことができるものというのが、よく技術記事で見かける表現です。
Dartのコールバックも同じものなのか深掘りしてみることにしました。

Signature of callbacks that have no arguments and return no data.

引数を持たず、データを返さないコールバックのシグネチャ。

typedefsというワードがでてきましたね?、これはなんでしょうか?、Dartの公式リファレンスを見て調べてみました。
https://dart.dev/language/typedefs

Typedefs(型定義という意味)

A type alias—often called a typedef because it’s declared with the keyword typedef—is a concise way to refer to a type. Here’s an example of declaring and using a type alias named IntList:

型エイリアスは、typedefというキーワードで宣言されるため、typedefと呼ばれることもありますが、型を参照するための簡潔な方法です。ここでは、IntListという名前の型エイリアスを宣言し、使用する例を示します。

typedef IntList = List<int>;
IntList il = [1, 2, 3];

A type alias can have type parameters:

型エイリアスは、型パラメータを持つことができる。

typedef ListMapper<X> = Map<X, List<X>>;
Map<String, List<String>> m1 = {}; // Verbose.
ListMapper<String> m2 = {}; // 同じことでも、より短く、より分かりやすく.

Version note: Before 2.13, typedefs were restricted to function types. Using the new typedefs requires a language version of at least 2.13.

バージョン情報:2.13以前は、型定義は関数型に限定されていました。新しい型定義を使用するには、少なくとも2.13の言語バージョンが必要です。

We recommend using inline function types instead of typedefs for functions, in most situations. However, function typedefs can still be useful:

ほとんどの場合,関数の型定義は使用せず,インライン関数型を使用することをお勧めします.しかし、関数の型定義はまだ役に立つことがあります。

typedef Compare<T> = int Function(T a, T b);

int sort(int a, int b) => a - b;

void main() {
  assert(sort is Compare<int>); // True!
}

Typedefsがあるといいこと!

関数に型を定義することができる。今回だとボタンコンポーネントに、VoidCallback型の変数を作成して、コールバック関数に渡すことができる関数の型を指定できる。
void型の関数は渡せるけど、int型の関数を引数として渡すとエラーが発生する。


切りわけたWidgetクラスに関数を引数として渡して、ボタンを押すとカウンターが増えるのと、トーストを出すプログクラムを作ってみました!
カウンターだけだと面白くないですよね😅

こちらのパッケージを追加
もしビルドしてエラーが出たら、アプリを一度削除してもう一度ビルドすると治ります?
トースト独特のエラーのようです🤔
https://pub.dev/packages/fluttertoast

完成品のコード

main.dart
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const CallbackExample(),
    );
  }
}

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

  
  State<CallbackExample> createState() => _CallbackExampleState();
}

class _CallbackExampleState extends State<CallbackExample> {
  int count = 0;
  // コールバック関数に引数として渡す関数
  void increment() {
    setState(() {});
    count++;
    // fluttertoastのコード
    Fluttertoast.showToast(
        msg: "callback $count",
        toastLength: Toast.LENGTH_SHORT,
        gravity: ToastGravity.CENTER,
        timeInSecForIosWeb: 1,
        backgroundColor: Colors.red,
        textColor: Colors.white,
        fontSize: 16.0);
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Callback$count'),
      ),
      floatingActionButton: VoidCallbackButton(callback: increment),
    );
  }
}

// FloatingActionButtonを切り分けたWidget
class VoidCallbackButton extends StatelessWidget {
  const VoidCallbackButton({
    super.key,
    required this.callback,
  });
  // VoidCallback
  final VoidCallback callback;

  
  Widget build(BuildContext context) {
    return FloatingActionButton(
      onPressed: callback,
      tooltip: 'Increment',
      child: const Icon(Icons.add),
    );
  }
}

実行結果

まとめ

コールバックは、どんな場面で使うかというと、Widgetを切り分けて部品化してあるWidgetクラスやメソッドに引数として渡すときです。
覚えておくと使う機会があると思うので、皆さんもコールバックでプログラムを作るのをやってみてください。

Discussion