Flutterで"HelloWorld"やってみた


はじめに

はじめまして。
FlutterによるHelloWorldをやってみたので、どうやったのか書いてみたいと思います。
状態管理は、Flutter_HooksとHooks_Riverpod、StateNotifierを使いました。モデルはfreezedで生成しています。
初心者なので間違っている点はご指摘ください。学びになりますので嬉しいです。

開発環境

OS
macOS Catalina 10.15.7

パッケージ

pubspec.yaml
environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.3
  flutter_hooks: ^0.14.0
  hooks_riverpod: ^0.11.0
  freezed_annotation: ^0.11.0+1
  state_notifier: ^0.6.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  freezed: ^0.11.6
  build_runner:
  analyzer: 0.39.5

こんな風になるよ

コード抜粋

main.dart
void main() => runApp(ProviderScope(child: MyApp()));

まずはviewを切り替えるだけの役割を持った、main.dartです。
RiverpodはプロジェクトのルートでProviderScope()を呼び出すようになっているようです。


hello_model.dart
import ...
// ↓ partを指定
part 'hello_model.freezed.dart';

@freezed
abstract class HelloModel with _$HelloModel {
  factory HelloModel({
    @Default('初めまして') String greeting,
    @Default(0) int count,
  }) = _HelloModel;
}

続いて、データだけを持つモデル、そのモデルの状態を更新するコントローラーを作成します。
freezedを使い、immutableなモデルを作ります。
partを指定することで、**.freezed.dartファイルを生成できます。

build_runnerパッケージでコードを生成する必要があるので、ターミナルでflutter pub run build_runner buildを実行する。この時のエラー対策のために、analyzerパッケージを入れています。


hello_model.dart
class HelloModelController extends StateNotifier<HelloModel> {
  HelloModelController() : super(HelloModel());
  // countによってあいさつを切り替えるメソッド
  hello() {
    state.count.isOdd
        ? state = state.copyWith(greeting: 'hello')
        : state = state.copyWith(greeting: 'こんにちは');
  }
  // countを10以下でインクリメントするメソッド
  increment() {
    state = state.count >= 10
        ? state.copyWith(count: 1)
        : state.copyWith(count: state.count + 1);
  }

モデルのコントローラーは、StateNotifierで拡張するので、変数はstateだけ使えます。ここでのstateはHello Modelの状態のことです。(たぶん)
状態の変数を変更することにより、一つの変数(state)で複数の状態(greeting, count)を変更できると認識しています。


ここからは、Hello Modelのviewを書いていきます。

hello_view.dart
final controllerProvider = StateNotifierProvider((_) => HelloModelController());

class HelloView extends HookWidget {
  @override
  Widget build(BuildContext context) {
    // (*) useProviderをHookWidget内のbuildメソッドから呼び出す
    final helloState = useProvider(controllerProvider.state);
    final helloController = useProvider(controllerProvider);

    return Scaffold();

まずは、クラスの外でStateNotifierProviderを使い、provider(ここではcontrollerProvider)を作ります。providerはimmutableでなければならないので、finalで指定します。

そして、viewをHookWidgetで拡張します。
HookWidgetのbuildメソッド内に、useProviderメソッドを用いて、providerを使うための変数を書きます。

helloState -> greetingを表示するために使います。
helloController -> counterを更新するためのコントローラーとして使います。


hello_view.dart
class HelloView extends HookWidget {
  @override
  Widget build(BuildContext context) {
    ...
    return Scaffold(
      body: Center(
        child: Container(...),
          child: Center(
            child: Text(
              helloState.greeting,
            ),

Textウィジェットでgreetingを呼び出します。


hello_view.dart
class HelloView extends HookWidget {
  @override
  Widget build(BuildContext context) {
    ...
    return Scaffold(
      body: Center(
        child: Container(...),
          child: Center(
            child: Text(...),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          helloController.hello(); // ①
          helloController.increment(); // ②
        },
        ...
      ),

①で表示するあいさつの状態を更新します。
②でカウントの状態を更新します。

以上で各要所の説明は終わりです。

全コード

GitHub: yusuketanabe/Flutter_HelloWorld

ありがとうございました。