カテゴリー: ニュース
ニュース
Flutterで状態管理あれこれ2
状態管理の元となるInheritedWidgetを理解するためにカウンターアプリを改造して実装してみましたがとても複雑でした。
それで流行りのパッケージを実装してみました。使いやすいように InheritedWidget をラップしているのでコードは短くなるのですが、バージョンによって細かく記述方法が異なりなり正解にたどり着くのが大変です。
flutter_hooks: ^0.17.0 hooks_riverpod: ^0.14.0+4 state_notifier: ^0.7.0
import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; final viewModel = StateNotifierProvider((_) => ViewModel()); class ViewModel extends StateNotifier<int> { ViewModel() : super(0); void increment() => state++; void decrement() => state--; } void main() { runApp( ProviderScope( child: CounterApp(), ), ); } class CounterApp extends HookWidget { @override Widget build(BuildContext context) { final _viewModel = useProvider(viewModel); return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('CounterApp')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), Text( _viewModel.toString(), style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ FloatingActionButton( heroTag: 'increment', onPressed: () => context.read(viewModel.notifier).increment(), child: Icon(Icons.add), ), Gap(15), FloatingActionButton( heroTag: 'decrement', onPressed: () => context.read(viewModel.notifier).decrement(), child: Icon(Icons.remove_circle_outline), ), ], ), ), ); } }
このコードもパッケージのバージョンがちょっとでも上がれば直さなくなると思います。
実機のスクリーンショットは
flutter screenshot
で撮れます。プロジェクトフォルダーに画像が保存される。
Flutterで角を丸くする
TextFieldやDropdownButtonの角を丸くしてみた。結局ConainerのBorderを丸くして角が丸くなったように見せるだけだった。
import 'package:flutter/material.dart'; import 'package:gap/gap.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: 'Flutter Demo Home Page'), ); } } 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; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { String dropdownValue = 'One'; return Scaffold( backgroundColor: Colors.grey, appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ ClipRRect( borderRadius: BorderRadius.all(Radius.circular(30)), child: Container( width: 200, height: 100, color: Colors.yellow, child: Padding( padding: const EdgeInsets.all(8), child: const TextField( obscureText: true, decoration: InputDecoration( border: InputBorder.none, labelText: 'Pass', ), ), ), ), ), Gap(20), Container( padding: const EdgeInsets.symmetric(horizontal: 5), width: 200, decoration: BoxDecoration( border: Border.all(color: Colors.blue), borderRadius: BorderRadius.circular(20), ), child: const TextField( obscureText: true, decoration: InputDecoration( border: InputBorder.none, labelText: 'Pass', ), ), ), Gap(20), Container( padding: const EdgeInsets.symmetric(horizontal: 5), width: 200, decoration: BoxDecoration( border: Border.all(color: Colors.blue), borderRadius: BorderRadius.circular(20), ), child: DropdownButton<String>( value: dropdownValue, icon: const Icon(Icons.arrow_downward), iconSize: 24, elevation: 16, style: const TextStyle(color: Colors.deepPurple), onChanged: (String? newValue) {}, items: <String>['One', 'Two', 'Free', 'Four'] .map<DropdownMenuItem<String>>((String value) { return DropdownMenuItem<String>( value: value, child: Text(value), ); }).toList(), ), ), Gap(20), Text( 'You have pushed the button this many times:', style: TextStyle(color: Colors.white), ), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), ); } }
Flutterの状態管理あれこれ
状態管理の要点はその状態に影響を受けるWidgetのみが状態変化に対する処理を行えるように効率化することです。
InheritedWidget
Flutter自身を構成するWidgetの一つ。Widgetツリーの配下に効率的に情報を伝える仕組みを提供します。
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage( key: null, child: Scaffold( appBar: AppBar( title: Text("Inherited Widget Sample"), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ WidgetNumText(), WidgetCenterText( key: null, ), ], ), ), floatingActionButton: WidgetIncrementBtn(), ), ), ); } } class MyHomePage extends StatefulWidget { MyHomePage({required Key? key, required this.child}) : super(key: key); final Widget child; @override _MyHomePageState createState() => _MyHomePageState(); static _MyHomePageState of(BuildContext context, {bool rebuild = true}) { return rebuild ? (context.dependOnInheritedWidgetOfExactType<_InheritedWidget>() as _InheritedWidget) .data : (context .getElementForInheritedWidgetOfExactType<_InheritedWidget>()! .widget as _InheritedWidget) .data; } } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return _InheritedWidget( child: widget.child, data: this, ); } } class WidgetIncrementButton extends StatelessWidget { @override Widget build(BuildContext context) { final _MyHomePageState state = MyHomePage.of(context, rebuild: false); return FloatingActionButton( onPressed: () => state._incrementCounter(), tooltip: 'Increment', child: Icon(Icons.add), ); } } class _InheritedWidget extends InheritedWidget { _InheritedWidget({ Key? key, required Widget child, required this.data, }) : super(key: key, child: child); final _MyHomePageState data; @override bool updateShouldNotify(InheritedWidget oldWidget) => true; } class WidgetNumText extends StatelessWidget { @override Widget build(BuildContext context) { final _MyHomePageState state = MyHomePage.of(context); return Text( '${state._counter}', style: Theme.of(context).textTheme.headline4, ); } } class WidgetIncrementBtn extends StatelessWidget { @override Widget build(BuildContext context) { final _MyHomePageState state = MyHomePage.of(context, rebuild: false); return FloatingActionButton( onPressed: () => state._incrementCounter(), tooltip: 'Increment', child: Icon(Icons.add), ); } } class WidgetCenterText extends StatelessWidget { const WidgetCenterText({required Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Text('You have pushed the button this many times:'); } }
Memo
Shader compilation errorが出たら
エミュレーターからアプリを消してflutter cleanする
Provider
InheritedWidgetのラッパークラスで状態管理とDI機能を提供します。
StateNotifer
状態管理パッケージでProviderをベースに作られている。同じ作者。
Android Studioは公式の説明通りにインストールしFlutterとDartのプラグインを追加した。
Google Pixelを有効にするためのコマンド echo "SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"18d1\", MODE=\"0666\", GROUP=\"plugdev\"" > /tmp/51-android.rules sudo cp /tmp/51-android.rules /etc/udev/rules.d/51-android.rules Flutterのインストール git clone https://github.com/flutter/flutter sudo mv flutter /usr/local/ sudo apt install clang curl pkg-config ninja-sudo apt install clang curl pkg-config ninja-build cmake libgtk-3-dev libblkid-dev liblzma-dev unzipbuild cmake libgtk-3-dev libblkid-dev liblzma-dev unzip flutter config --enable-linux-desktop flutter doctor Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel master, 2.5.0-7.0.pre.182, on Ubuntu 20.04.3 LTS 5.4.0-83-generic, locale ja_JP.UTF-8) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2) [✓] Chrome - develop for the web [✓] Linux toolchain - develop for Linux desktop [✓] Android Studio (version 2020.3) [✓] Android Studio [✓] VS Code (version 1.59.1) [✓] Connected device (4 available)
更にKindle Fire 7 で実行してみた。
狭くてWindows PCの置き場が無くなった
ので素直にupgradeしてみた。
╔════════════════════════════════════════════════════════════════════════════╗ ║ A new version of Flutter is available! ║ ║ ║ ║ To update to the latest version, run "flutter upgrade". ║ ╚════════════════════════════════════════════════════════════════════════════╝
developer@Mac-mini my_app_01 % flutter upgrade Upgrading Flutter to 2.5.0-7.0.pre.80 from 2.4.0-5.0.pre.166 in /Users/developer/Documents/flutter... Downloading Dart SDK from Flutter engine a447901bc58b277a986e665520c42ed1ad2cb945... % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 0 221M 0 1340 0 0 1956 0 32:58:21 --:--:-- 32:58:21 1953 0 221M 0 1134k 0 0 733k 0 0:05:09 0:00:01 0:05:08 732k 1 221M 1 2462k 0 0 964k 0 0:03:55 0:00:02 0:03:53 964k 1 221M 1 3694k 0 0 1038k 0 0:03:38 0:00:03 0:03:35 1038k 2 221M 2 4750k 0 0 1043k 0 0:03:37 0:00:04 0:03:33 1043k 2 221M 2 5998k 0 0 1080k 0 0:03:29 0:00:05 0:03:24 1231k 3 221M 3 7150k 0 0 1087k 0 0:03:28 0:00:06 0:03:22 1196k 3 221M 3 8366k 0 0 1108k 0 0:03:24 0:00:07 0:03:17 1181k 4 221M 4 9390k 0 0 1098k 0 0:03:26 0:00:08 0:03:18 1141k 4 221M 4 10.4M 0 0 1117k 0 0:03:22 0:00:09 0:03:13 1184k 5 221M 5 11.5M 0 0 1120k 0 0:03:22 0:00:10 0:03:12 1164k 5 221M 5 12.7M 0 0 1125k 0 0:03:21 0:00:11 0:03:10 1175k 6 221M 6 13.8M 0 0 1128k 0 0:03:20 0:00:12 0:03:08 1159k 6 221M 6 14.9M 0 0 1131k 0 0:03:20 0:00:13 0:03:07 1187k 7 221M 7 16.1M 0 0 1137k 0 0:03:19 0:00:14 0:03:05 1175k 7 221M 7 17.3M 0 0 1138k 0 0:03:19 0:00:15 0:03:04 1177k 8 221M 8 18.3M 0 0 1130k 0 0:03:20 0:00:16 0:03:04 1142k 8 221M 8 19.3M 0 0 1130k 0 0:03:20 0:00:17 0:03:03 1134k 9 221M 9 20.4M 0 0 1130k 0 0:03:20 0:00:18 0:03:02 1129k 9 221M 9 21.3M 0 0 1116k 0 0:03:23 0:00:19 0:03:04 1056k 10 221M 10 22.3M 0 0 1111k 0 0:03:23 0:00:20 0:03:03 1027k 10 221M 10 23.2M 0 0 1103k 0 0:03:25 0:00:21 0:03:04 1009k 11 221M 11 24.5M 0 0 1112k 0 0:03:23 0:00:22 0:03:01 1048k 11 221M 11 25.6M 0 0 1114k 0 0:03:23 0:00:23 0:03:00 1054k 12 221M 12 26.7M 0 0 1113k 0 0:03:23 0:00:24 0:02:59 1102k 12 221M 12 27.7M 0 0 1113k 0 0:03:23 0:00:25 0:02:58 1119k 12 221M 12 28.7M 0 0 1107k 0 0:03:24 0:00:26 0:02:58 1126k 13 221M 13 29.6M 0 0 1101k 0 0:03:25 0:00:27 0:02:58 1055k 13 221M 13 30.8M 0 0 1105k 0 0:03:25 0:00:28 0:02:57 1065k 14 221M 14 32.0M 0 0 1109k 0 0:03:24 0:00:29 0:02:55 1088k 14 221M 14 33.1M 0 0 1111k 0 0:03:23 0:00:30 0:02:53 1105k 15 221M 15 34.2M 0 0 1113k 0 0:03:23 0:00:31 0:02:52 1142k 16 221M 16 35.4M 0 0 1114k 0 0:03:23 0:00:32 0:02:51 1186k 16 221M 16 36.4M 0 0 1111k 0 0:03:24 0:00:33 0:02:51 1141k 16 221M 16 37.1M 0 0 1100k 0 0:03:25 0:00:34 0:02:51 1049k 16 221M 16 37.3M 0 0 1076k 0 0:03:30 0:00:35 0:02:55 857k 16 221M 16 37.5M 0 0 1051k 0 0:03:35 0:00:36 0:02:59 662k 17 221M 17 38.5M 0 0 1050k 0 0:03:35 0:00:37 0:02:58 631k 17 221M 17 39.6M 0 0 1052k 0 0:03:35 0:00:38 0:02:57 659k 18 221M 18 40.7M 0 0 1055k 0 0:03:34 0:00:39 0:02:55 739k 18 221M 18 41.7M 0 0 1053k 0 0:03:35 0:00:40 0:02:55 897k 19 221M 19 42.6M 0 0 1050k 0 0:03:35 0:00:41 0:02:54 1046k 19 221M 19 43.7M 0 0 1052k 0 0:03:35 0:00:42 0:02:53 1066k 20 221M 20 44.9M 0 0 1055k 0 0:03:34 0:00:43 0:02:51 1078k 20 221M 20 45.8M 0 0 1053k 0 0:03:35 0:00:44 0:02:51 1044k 21 221M 21 47.1M 0 0 1060k 0 0:03:33 0:00:45 0:02:48 1110k 21 221M 21 48.1M 0 0 1059k 0 0:03:34 0:00:46 0:02:48 1129k 22 221M 22 49.2M 0 0 1060k 0 0:03:33 0:00:47 0:02:46 1133k 22 221M 22 50.5M 0 0 1065k 0 0:03:32 0:00:48 0:02:44 1152k 23 221M 23 51.6M 0 0 1066k 0 0:03:32 0:00:49 0:02:43 1183k 23 221M 23 52.7M 0 0 1068k 0 0:03:32 0:00:50 0:02:42 1141k 24 221M 24 53.6M 0 0 1065k 0 0:03:32 0:00:51 0:02:41 1119k 24 221M 24 54.6M 0 0 1065k 0 0:03:32 0:00:52 0:02:40 1108k 24 221M 24 54.8M 0 0 1049k 0 0:03:36 0:00:53 0:02:43 891k 24 221M 24 55.1M 0 0 1034k 0 0:03:39 0:00:54 0:02:45 713k 25 221M 25 56.1M 0 0 1034k 0 0:03:39 0:00:55 0:02:44 693k 25 221M 25 57.0M 0 0 1033k 0 0:03:39 0:00:56 0:02:43 707k 26 221M 26 58.2M 0 0 1035k 0 0:03:38 0:00:57 0:02:41 726k 26 221M 26 59.3M 0 0 1038k 0 0:03:38 0:00:58 0:02:40 922k 27 221M 27 60.4M 0 0 1038k 0 0:03:38 0:00:59 0:02:39 1080k 27 221M 27 61.2M 0 0 1036k 0 0:03:38 0:01:00 0:02:38 1057k 28 221M 28 62.4M 0 0 1038k 0 0:03:38 0:01:01 0:02:37 1094k 28 221M 28 63.6M 0 0 1041k 0 0:03:37 0:01:02 0:02:35 1100k 29 221M 29 64.7M 0 0 1042k 0 0:03:37 0:01:03 0:02:34 1095k 29 221M 29 65.8M 0 0 1045k 0 0:03:36 0:01:04 0:02:32 1124k 30 221M 30 67.0M 0 0 1046k 0 0:03:36 0:01:05 0:02:31 1175k 30 221M 30 68.0M 0 0 1047k 0 0:03:36 0:01:06 0:02:30 1159k 31 221M 31 69.1M 0 0 1047k 0 0:03:36 0:01:07 0:02:29 1121k 31 221M 31 70.2M 0 0 1048k 0 0:03:36 0:01:08 0:02:28 1122k 32 221M 32 71.3M 0 0 1049k 0 0:03:35 0:01:09 0:02:26 1110k 32 221M 32 72.3M 0 0 1050k 0 0:03:35 0:01:10 0:02:25 1096k 33 221M 33 73.4M 0 0 1051k 0 0:03:35 0:01:11 0:02:24 1104k 33 221M 33 74.6M 0 0 1053k 0 0:03:35 0:01:12 0:02:23 1134k 34 221M 34 75.7M 0 0 1054k 0 0:03:35 0:01:13 0:02:22 1134k 34 221M 34 76.8M 0 0 1054k 0 0:03:35 0:01:14 0:02:21 1121k 35 221M 35 77.8M 0 0 1054k 0 0:03:35 0:01:15 0:02:20 1110k 35 221M 35 78.9M 0 0 1056k 0 0:03:34 0:01:16 0:02:18 1123k 36 221M 36 80.0M 0 0 1056k 0 0:03:34 0:01:17 0:02:17 1107k 36 221M 36 81.0M 0 0 1056k 0 0:03:34 0:01:18 0:02:16 1081k 36 221M 36 81.9M 0 0 1054k 0 0:03:35 0:01:19 0:02:16 1052k 37 221M 37 82.8M 0 0 1053k 0 0:03:35 0:01:20 0:02:15 1043k 38 221M 38 84.2M 0 0 1057k 0 0:03:34 0:01:21 0:02:13 1070k 38 221M 38 85.2M 0 0 1057k 0 0:03:34 0:01:22 0:02:12 1074k 38 221M 38 86.3M 0 0 1058k 0 0:03:34 0:01:23 0:02:11 1088k 39 221M 39 87.2M 0 0 1056k 0 0:03:34 0:01:24 0:02:10 1083k 39 221M 39 87.4M 0 0 1046k 0 0:03:36 0:01:25 0:02:11 926k 39 221M 39 87.6M 0 0 1037k 0 0:03:38 0:01:26 0:02:12 713k 40 221M 40 88.9M 0 0 1039k 0 0:03:38 0:01:27 0:02:11 742k 40 221M 40 90.0M 0 0 1041k 0 0:03:37 0:01:28 0:02:09 761k 41 221M 41 91.2M 0 0 1043k 0 0:03:37 0:01:29 0:02:08 822k 41 221M 41 92.0M 0 0 1041k 0 0:03:37 0:01:30 0:02:07 952k 41 221M 41 92.7M 0 0 1037k 0 0:03:38 0:01:31 0:02:07 1038k 42 221M 42 93.7M 0 0 1036k 0 0:03:38 0:01:32 0:02:06 983k 42 221M 42 94.5M 0 0 1035k 0 0:03:39 0:01:33 0:02:06 921k 43 221M 43 95.6M 0 0 1035k 0 0:03:38 0:01:34 0:02:04 897k 43 221M 43 96.5M 0 0 1035k 0 0:03:39 0:01:35 0:02:04 924k 44 221M 44 97.7M 0 0 1036k 0 0:03:38 0:01:36 0:02:02 1015k 44 221M 44 98.8M 0 0 1037k 0 0:03:38 0:01:37 0:02:01 1057k 45 221M 45 100M 0 0 1039k 0 0:03:38 0:01:38 0:02:00 1116k 45 221M 45 101M 0 0 1040k 0 0:03:37 0:01:39 0:01:58 1131k 46 221M 46 102M 0 0 1039k 0 0:03:38 0:01:40 0:01:58 1123k 46 221M 46 103M 0 0 1039k 0 0:03:38 0:01:41 0:01:57 1099k 47 221M 47 104M 0 0 1040k 0 0:03:37 0:01:42 0:01:55 1097k 47 221M 47 105M 0 0 1039k 0 0:03:38 0:01:43 0:01:55 1046k 47 221M 47 106M 0 0 1038k 0 0:03:38 0:01:44 0:01:54 1008k 48 221M 48 107M 0 0 1039k 0 0:03:38 0:01:45 0:01:53 1050k 48 221M 48 108M 0 0 1042k 0 0:03:37 0:01:46 0:01:51 1095k 49 221M 49 109M 0 0 1043k 0 0:03:37 0:01:47 0:01:50 1090k 49 221M 49 110M 0 0 1043k 0 0:03:37 0:01:48 0:01:49 1128k 50 221M 50 111M 0 0 1043k 0 0:03:37 0:01:49 0:01:48 1136k 50 221M 50 112M 0 0 1041k 0 0:03:37 0:01:50 0:01:47 1074k 51 221M 51 113M 0 0 1041k 0 0:03:37 0:01:51 0:01:46 1033k 51 221M 51 114M 0 0 1042k 0 0:03:37 0:01:52 0:01:45 1026k 52 221M 52 115M 0 0 1041k 0 0:03:37 0:01:53 0:01:44 992k 52 221M 52 116M 0 0 1040k 0 0:03:37 0:01:54 0:01:43 984k 53 221M 53 117M 0 0 1042k 0 0:03:37 0:01:55 0:01:42 1069k 53 221M 53 118M 0 0 1043k 0 0:03:37 0:01:56 0:01:41 1089k 54 221M 54 119M 0 0 1043k 0 0:03:37 0:01:57 0:01:40 1080k 54 221M 54 121M 0 0 1045k 0 0:03:36 0:01:58 0:01:38 1133k 55 221M 55 122M 0 0 1046k 0 0:03:36 0:01:59 0:01:37 1176k 55 221M 55 123M 0 0 1047k 0 0:03:36 0:02:00 0:01:36 1152k 56 221M 56 124M 0 0 1048k 0 0:03:36 0:02:01 0:01:35 1154k 56 221M 56 125M 0 0 1048k 0 0:03:36 0:02:02 0:01:34 1164k 57 221M 57 126M 0 0 1049k 0 0:03:36 0:02:03 0:01:33 1138k 57 221M 57 127M 0 0 1051k 0 0:03:35 0:02:04 0:01:31 1168k 58 221M 58 128M 0 0 1051k 0 0:03:35 0:02:05 0:01:30 1155k 58 221M 58 130M 0 0 1052k 0 0:03:35 0:02:06 0:01:29 1167k 59 221M 59 131M 0 0 1053k 0 0:03:35 0:02:07 0:01:28 1181k 59 221M 59 132M 0 0 1053k 0 0:03:35 0:02:08 0:01:27 1158k 60 221M 60 132M 0 0 1051k 0 0:03:35 0:02:09 0:01:26 1053k 60 221M 60 133M 0 0 1050k 0 0:03:35 0:02:10 0:01:25 1018k 60 221M 60 134M 0 0 1049k 0 0:03:35 0:02:11 0:01:24 973k 61 221M 61 136M 0 0 1050k 0 0:03:35 0:02:12 0:01:23 957k 61 221M 61 137M 0 0 1051k 0 0:03:35 0:02:13 0:01:22 1007k 62 221M 62 138M 0 0 1052k 0 0:03:35 0:02:14 0:01:21 1084k 62 221M 62 139M 0 0 1053k 0 0:03:35 0:02:15 0:01:20 1135k 63 221M 63 140M 0 0 1054k 0 0:03:35 0:02:16 0:01:19 1167k 63 221M 63 141M 0 0 1054k 0 0:03:35 0:02:17 0:01:18 1168k 64 221M 64 142M 0 0 1055k 0 0:03:34 0:02:18 0:01:16 1159k 64 221M 64 143M 0 0 1054k 0 0:03:35 0:02:19 0:01:16 1108k 65 221M 65 144M 0 0 1055k 0 0:03:34 0:02:20 0:01:14 1120k 65 221M 65 145M 0 0 1054k 0 0:03:34 0:02:21 0:01:13 1068k 66 221M 66 146M 0 0 1054k 0 0:03:35 0:02:22 0:01:13 1051k 66 221M 66 147M 0 0 1054k 0 0:03:34 0:02:23 0:01:11 1038k 67 221M 67 148M 0 0 1054k 0 0:03:34 0:02:24 0:01:10 1057k 67 221M 67 149M 0 0 1053k 0 0:03:35 0:02:25 0:01:10 1001k 68 221M 68 151M 0 0 1055k 0 0:03:34 0:02:26 0:01:08 1079k 68 221M 68 151M 0 0 1054k 0 0:03:35 0:02:27 0:01:08 1052k 69 221M 69 152M 0 0 1054k 0 0:03:34 0:02:28 0:01:06 1045k 69 221M 69 154M 0 0 1055k 0 0:03:34 0:02:29 0:01:05 1066k 70 221M 70 155M 0 0 1056k 0 0:03:34 0:02:30 0:01:04 1138k 70 221M 70 156M 0 0 1057k 0 0:03:34 0:02:31 0:01:03 1111k 71 221M 71 157M 0 0 1057k 0 0:03:34 0:02:32 0:01:02 1158k 71 221M 71 158M 0 0 1058k 0 0:03:34 0:02:33 0:01:01 1170k 72 221M 72 159M 0 0 1058k 0 0:03:34 0:02:34 0:01:00 1164k 72 221M 72 160M 0 0 1059k 0 0:03:34 0:02:35 0:00:59 1135k 73 221M 73 162M 0 0 1060k 0 0:03:33 0:02:36 0:00:57 1153k 73 221M 73 163M 0 0 1060k 0 0:03:33 0:02:37 0:00:56 1145k 74 221M 74 164M 0 0 1060k 0 0:03:33 0:02:38 0:00:55 1122k 74 221M 74 165M 0 0 1059k 0 0:03:33 0:02:39 0:00:54 1099k 75 221M 75 166M 0 0 1059k 0 0:03:33 0:02:40 0:00:53 1081k 75 221M 75 167M 0 0 1059k 0 0:03:34 0:02:41 0:00:53 1025k 75 221M 75 168M 0 0 1059k 0 0:03:34 0:02:42 0:00:52 1027k 76 221M 76 169M 0 0 1060k 0 0:03:33 0:02:43 0:00:50 1070k 77 221M 77 170M 0 0 1061k 0 0:03:33 0:02:44 0:00:49 1105k 77 221M 77 171M 0 0 1062k 0 0:03:33 0:02:45 0:00:48 1128k 78 221M 78 172M 0 0 1062k 0 0:03:33 0:02:46 0:00:47 1158k 78 221M 78 173M 0 0 1061k 0 0:03:33 0:02:47 0:00:46 1128k 78 221M 78 174M 0 0 1061k 0 0:03:33 0:02:48 0:00:45 1077k 79 221M 79 175M 0 0 1060k 0 0:03:33 0:02:49 0:00:44 1047k 79 221M 79 176M 0 0 1061k 0 0:03:33 0:02:50 0:00:43 1027k 80 221M 80 177M 0 0 1059k 0 0:03:33 0:02:51 0:00:42 967k 80 221M 80 177M 0 0 1055k 0 0:03:34 0:02:52 0:00:42 837k 80 221M 80 178M 0 0 1050k 0 0:03:35 0:02:53 0:00:42 682k 80 221M 80 179M 0 0 1051k 0 0:03:35 0:02:54 0:00:41 724k 81 221M 81 180M 0 0 1051k 0 0:03:35 0:02:55 0:00:40 725k 81 221M 81 181M 0 0 1051k 0 0:03:35 0:02:56 0:00:39 786k 82 221M 82 182M 0 0 1052k 0 0:03:35 0:02:57 0:00:38 967k 82 221M 82 183M 0 0 1053k 0 0:03:35 0:02:58 0:00:37 1161k 83 221M 83 184M 0 0 1052k 0 0:03:35 0:02:59 0:00:36 1114k 83 221M 83 185M 0 0 1054k 0 0:03:34 0:03:00 0:00:34 1166k 84 221M 84 187M 0 0 1055k 0 0:03:34 0:03:01 0:00:33 1170k 85 221M 85 188M 0 0 1055k 0 0:03:34 0:03:02 0:00:32 1170k 85 221M 85 189M 0 0 1056k 0 0:03:34 0:03:03 0:00:31 1161k 85 221M 85 190M 0 0 1056k 0 0:03:34 0:03:04 0:00:30 1187k 86 221M 86 191M 0 0 1056k 0 0:03:34 0:03:05 0:00:29 1122k 86 221M 86 192M 0 0 1056k 0 0:03:34 0:03:06 0:00:28 1121k 87 221M 87 193M 0 0 1056k 0 0:03:34 0:03:07 0:00:27 1081k 87 221M 87 194M 0 0 1056k 0 0:03:34 0:03:08 0:00:26 1061k 88 221M 88 195M 0 0 1056k 0 0:03:34 0:03:09 0:00:25 1060k 88 221M 88 196M 0 0 1056k 0 0:03:34 0:03:10 0:00:24 1061k 89 221M 89 197M 0 0 1056k 0 0:03:34 0:03:11 0:00:23 1056k 89 221M 89 198M 0 0 1057k 0 0:03:34 0:03:12 0:00:22 1093k 90 221M 90 199M 0 0 1057k 0 0:03:34 0:03:13 0:00:21 1111k 90 221M 90 201M 0 0 1058k 0 0:03:34 0:03:14 0:00:20 1125k 91 221M 91 202M 0 0 1059k 0 0:03:34 0:03:15 0:00:19 1151k 91 221M 91 203M 0 0 1058k 0 0:03:34 0:03:16 0:00:18 1138k 92 221M 92 204M 0 0 1059k 0 0:03:34 0:03:17 0:00:17 1126k 92 221M 92 205M 0 0 1059k 0 0:03:33 0:03:18 0:00:15 1122k 93 221M 93 206M 0 0 1060k 0 0:03:33 0:03:19 0:00:14 1128k 93 221M 93 207M 0 0 1060k 0 0:03:33 0:03:20 0:00:13 1132k 94 221M 94 208M 0 0 1061k 0 0:03:33 0:03:21 0:00:12 1159k 94 221M 94 210M 0 0 1062k 0 0:03:33 0:03:22 0:00:11 1172k 95 221M 95 211M 0 0 1062k 0 0:03:33 0:03:23 0:00:10 1174k 95 221M 95 212M 0 0 1062k 0 0:03:33 0:03:24 0:00:09 1171k 96 221M 96 213M 0 0 1063k 0 0:03:33 0:03:25 0:00:08 1169k 96 221M 96 214M 0 0 1063k 0 0:03:33 0:03:26 0:00:07 1154k 97 221M 97 215M 0 0 1064k 0 0:03:33 0:03:27 0:00:06 1148k 97 221M 97 216M 0 0 1064k 0 0:03:33 0:03:28 0:00:05 1142k 98 221M 98 217M 0 0 1065k 0 0:03:32 0:03:29 0:00:03 1154k 98 221M 98 218M 0 0 1065k 0 0:03:32 0:03:30 0:00:02 1131k 98 221M 98 219M 0 0 1061k 0 0:03:33 0:03:31 0:00:02 954k 99 221M 99 219M 0 0 1056k 0 0:03:34 0:03:32 0:00:02 751k 99 221M 99 220M 0 0 1055k 0 0:03:34 0:03:33 0:00:01 682k 99 221M 99 221M 0 0 1056k 0 0:03:34 0:03:34 --:--:-- 702k 100 221M 100 221M 0 0 1056k 0 0:03:34 0:03:34 --:--:-- 616k Building flutter tool... Upgrading engine... Downloading android-arm-profile/darwin-x64 tools... 3.2s Downloading android-arm-release/darwin-x64 tools... 2,600ms Downloading android-arm64-profile/darwin-x64 tools... 3.4s Downloading android-arm64-release/darwin-x64 tools... 2,644ms Downloading android-x64-profile/darwin-x64 tools... 2,881ms Downloading android-x64-release/darwin-x64 tools... 2,609ms Downloading android-x86 tools... 25.7s Downloading android-x64 tools... 21.5s Downloading android-arm tools... 10.1s Downloading android-arm-profile tools... 5.2s Downloading android-arm-release tools... 4.4s Downloading android-arm64 tools... 10.9s Downloading android-arm64-profile tools... 6.0s Downloading android-arm64-release tools... 4.6s Downloading android-x64-profile tools... 6.6s Downloading android-x64-release tools... 4.7s Downloading android-x86-jit-release tools... 7.3s Downloading ios tools... 48.6s Downloading ios-profile tools... 39.4s Downloading ios-release tools... 188.4s Downloading Web SDK... 32.5s Downloading package sky_engine... 1,729ms Downloading flutter_patched_sdk tools... 4.1s Downloading flutter_patched_sdk_product tools... 3.5s Downloading darwin-x64 tools... 28.6s Downloading darwin-x64/font-subset tools... 1,248ms Flutter 2.5.0-7.0.pre.80 • channel master • https://github.com/flutter/flutter.git Framework • revision 1422bfa723 (71 minutes ago) • 2021-08-14 04:02:06 -0400 Engine • revision a447901bc5 Tools • Dart 2.15.0 (build 2.15.0-15.0.dev) Running flutter doctor... Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel master, 2.5.0-7.0.pre.80, on macOS 11.5.1 20G80 darwin-x64, locale ja-JP) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3) [✓] Xcode - develop for iOS and macOS [✓] Chrome - develop for the web [✓] Android Studio (version 2020.3) [✓] VS Code (version 1.59.0) [✓] Connected device (3 available) • No issues found! developer@Mac-mini my_app_01 %
無事にNo issues found!と出た。良かった。
lib/my_first_page.dart
import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class MyFirstPage extends StatefulWidget { const MyFirstPage({Key? key}) : super(key: key); @override State<MyFirstPage> createState() => _MyFirstPageState(); } class _MyFirstPageState extends State<MyFirstPage> { late TextEditingController _controller; bool isChecked = false; @override void initState() { super.initState(); _controller = TextEditingController(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { Color getColor(Set<MaterialState> states) { const Set<MaterialState> interactiveStates = <MaterialState>{ MaterialState.pressed, MaterialState.hovered, MaterialState.focused, }; if (states.any(interactiveStates.contains)) { return Colors.blue; } return Colors.red; } String dropdownValue = 'One'; return Scaffold( appBar: AppBar( title: Text(AppLocalizations.of(context)!.firstPage), ), body: Container( padding: const EdgeInsets.all(8), child: Column( children: <Widget>[ Text(AppLocalizations.of(context)!.firstPage), TextField( controller: _controller, onSubmitted: (String value) async { await showDialog<void>( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Title'), content: Text( '"$value", which has length ${value.characters.length}.'), actions: <Widget>[ TextButton( onPressed: () { Navigator.pop(context); }, child: const Text('OK'), ), ], ); }, ); }, ), Checkbox( checkColor: Colors.white, fillColor: MaterialStateProperty.resolveWith(getColor), value: isChecked, onChanged: (bool? value) { setState(() { isChecked = value!; }); }), DropdownButton<String>( value: dropdownValue, icon: const Icon(Icons.arrow_downward), iconSize: 24, elevation: 16, style: const TextStyle(color: Colors.deepPurple), underline: Container( height: 2, color: Colors.deepPurpleAccent, ), onChanged: (String? newValue) { setState(() { dropdownValue = newValue!; }); }, items: <String>['One', 'Two', 'Free', 'Four'] .map<DropdownMenuItem<String>>((String value) { return DropdownMenuItem<String>( value: value, child: Text(value), ); }).toList(), ), ], ), ), ); } }
lib/my_first_page.dart
import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class MyFirstPage extends StatefulWidget { const MyFirstPage({Key? key}) : super(key: key); @override State<MyFirstPage> createState() => _MyFirstPageState(); } class _MyFirstPageState extends State<MyFirstPage> { late TextEditingController _controller; bool isChecked = false; @override void initState() { super.initState(); _controller = TextEditingController(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { Color getColor(Set<MaterialState> states) { const Set<MaterialState> interactiveStates = <MaterialState>{ MaterialState.pressed, MaterialState.hovered, MaterialState.focused, }; if (states.any(interactiveStates.contains)) { return Colors.blue; } return Colors.red; } return Scaffold( appBar: AppBar( title: Text(AppLocalizations.of(context)!.firstPage), ), body: Container( padding: const EdgeInsets.all(8), child: Column( children: <Widget>[ Text(AppLocalizations.of(context)!.firstPage), TextField( controller: _controller, onSubmitted: (String value) async { await showDialog<void>( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Title'), content: Text( '"$value", which has length ${value.characters.length}.'), actions: <Widget>[ TextButton( onPressed: () { Navigator.pop(context); }, child: const Text('OK'), ), ], ); }, ); }, ), Checkbox( checkColor: Colors.white, fillColor: MaterialStateProperty.resolveWith(getColor), value: isChecked, onChanged: (bool? value) { setState(() { isChecked = value!; }); }), ], ), ), ); } }
lib/my_app.dart
import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:my_app_01/my_first_page.dart'; import 'package:my_app_01/my_home_page.dart'; class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, theme: ThemeData( primarySwatch: Colors.blue, ), home: DefaultTabController( length: 3, child: Scaffold( appBar: AppBar( bottom: const TabBar( tabs: [ Tab(icon: Icon(Icons.looks_one)), Tab(icon: Icon(Icons.looks_two)), Tab(icon: Icon(Icons.looks_3)), ], ), title: const Text('Tabs Demo'), ), body: const TabBarView( children: [ MyFirstPage(), Icon(Icons.looks_two), MyHomePage(title: 'Flutter Demo Home Page'), ], ), ), ), ); } }
lib/my_first_page.dart
import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class MyFirstPage extends StatefulWidget { const MyFirstPage({Key? key}) : super(key: key); @override State<MyFirstPage> createState() => _MyFirstPageState(); } class _MyFirstPageState extends State<MyFirstPage> { late TextEditingController _controller; @override void initState() { super.initState(); _controller = TextEditingController(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(AppLocalizations.of(context)!.firstPage), ), body: Container( padding: const EdgeInsets.all(8), child: Column( children: <Widget>[ const Text('First Page'), TextField( controller: _controller, onSubmitted: (String value) async { await showDialog<void>( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Title'), content: Text( '"$value", which has length ${value.characters.length}.'), actions: <Widget>[ TextButton( onPressed: () { Navigator.pop(context); }, child: const Text('OK'), ), ], ); }, ); }, ), ], ), ), ); } }
lib/l10n/app_en.arb
{ "helloWorld": "Hello World!", "@helloWorld": { "description": "The conventional newborn programmer greeting" }, "firstPage": "First Page","@firstPage": {"description": "First Page Title"} }
lib/l10n/app_ja.arb
{ "helloWorld": "こんにちは。", "firstPage": "最初のページ" }
アプリでよくある画面の下の方にタブバーを追加してみました。サンプルのまま追加しました。
lib/my_home_page.dart
import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _selectedIndex = 0; static const TextStyle optionStyle = TextStyle(fontSize: 30, fontWeight: FontWeight.bold); static const List<Widget> _widgetOptions = <Widget>[ Text( 'Index 0: Home', style: optionStyle, ), Text( 'Index 1: Business', style: optionStyle, ), Text( 'Index 2: School', style: optionStyle, ), ]; void _onItemTapped(int index) { setState(() { _selectedIndex = index; }); } int _counter = 0; 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(AppLocalizations.of(context)!.helloWorld), const Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. bottomNavigationBar: BottomNavigationBar( items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.home), label: 'Home', ), BottomNavigationBarItem( icon: Icon(Icons.business), label: 'Business', ), BottomNavigationBarItem( icon: Icon(Icons.school), label: 'School', ), ], currentIndex: _selectedIndex, selectedItemColor: Colors.amber[800], onTap: _onItemTapped, ), ); } }
Flutter AppにTabbarを追加する
タブで画面を切り替えられるようにTabbarを追加してみます。画面の上側に表示されるTabbarです。
lib/my_app.dart
import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:my_app_01/my_home_page.dart'; class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, theme: ThemeData( primarySwatch: Colors.blue, ), home: DefaultTabController( length: 3, child: Scaffold( appBar: AppBar( bottom: const TabBar( tabs: [ Tab(icon: Icon(Icons.looks_one)), Tab(icon: Icon(Icons.looks_two)), Tab(icon: Icon(Icons.looks_3)), ], ), title: const Text('Tabs Demo'), ), body: const TabBarView( children: [ Icon(Icons.looks_one), Icon(Icons.looks_two), MyHomePage(title: 'Flutter Demo Home Page'), ], ), ), ), ); } }
GoogleのMaterial Iconsは凄いですね。ダウンロードしてビルドプロジェクトにアイコン画像を登録しなくても、いきなりコード内で使用できます。アプリで使用するアイコンが全てMaterial Iconsだったら開発効率が良くなります。
Flutter Appの多言語化
アプリの開発途中から多言語化対応するとあちこち修正しなければならなくなるので最初から多言語化前提で開発を行います。日本語のみであったとしてもアプリとしては多言語化対応しているけれども日本語のみ設定されている状態が望ましいです。
l10n.yaml
arb-dir: lib/l10n template-arb-file: app_en.arb output-localization-file: app_localizations.dart
pubspec.yaml
dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter intl: ^0.17.0 # intl_translation: 0.17.10+1
intl_translation: 0.17.10+1はintl: ^0.17.0と合わないのでインストールできませんでした。
なので
return MaterialApp( onGenerateTitle: (BuildContext context) => DemoLocalizations.of(context).title,
以降はできません。
lib/my_app.dart
import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:my_app_01/my_home_page.dart'; class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } }
lib/my_home_page.dart
import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; 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(AppLocalizations.of(context)!.helloWorld), const Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); } }
lib/l10n/app_en.arb
{ "helloWorld": "Hello World!", "@helloWorld": { "description": "The conventional newborn programmer greeting" } }
lib/l10n/app_ja.arb
{ "helloWorld": "こんにちは。" }
実際のアプリを開発するときは、起動時の処理、アプリの初期、トップ画面は別のクラスにしそのソースファイルは分割されているのでDefaultのアプリもそのように分割してみます。
main.dart
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; 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>[ const Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); } }
分割後
main.dart
import 'package:flutter/material.dart'; import 'package:my_app_01/my_app.dart'; void main() { runApp(const MyApp()); }
my_app.dart
import 'package:flutter/material.dart'; import 'package:my_app_01/my_home_page.dart'; class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } }
my_home_page.dart
import 'package:flutter/material.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; 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>[ const Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); } }
Repositoryが無くてもgit init
Flutterのインストールで行った環境作り
.zshrc
export PATH=$PATH:/Applications/Android\ Studio.app/Contents/jre/Contents/Home/bin export PATH=$PATH:/Users/developer/Documents/flutter/bin export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jre/Contents/Home export PATH="$HOME/.rbenv/bin:$PATH" eval "$(rbenv init -)"
各環境
developer@Mac-mini my_app_01 % gem -v 3.2.22 developer@Mac-mini my_app_01 % ruby --version ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-darwin20] developer@Mac-mini my_app_01 % rbenv versions system * 3.0.2 (set by /Users/developer/.rbenv/version) developer@Mac-mini my_app_01 % brew -v Homebrew 3.2.6 Homebrew/homebrew-core (git revision f909c2126a; last commit 2021-08-08) Homebrew/homebrew-cask (git revision b4da68444e; last commit 2021-08-08) developer@Mac-mini my_app_01 % xcode-select --version xcode-select version 2384. developer@Mac-mini my_app_01 % gem list ffi *** LOCAL GEMS *** ffi (1.15.3) public_suffix (4.0.6) developer@Mac-mini my_app_01 % xcodebuild -version Xcode 13.0 Build version 13A5201i developer@Mac-mini my_app_01 % pod --version 1.10.2
developer@Mac-mini ~ % flutter doctor -v [✓] Flutter (Channel master, 2.4.0-5.0.pre.166, on macOS 11.5.1 20G80 darwin-x64, locale ja-JP) • Flutter version 2.4.0-5.0.pre.166 at /Users/developer/Documents/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 2dc11a85ff (2 weeks ago), 2021-07-22 17:56:03 -0700 • Engine revision fbbb3b3f7b • Dart version 2.14.0 (build 2.14.0-343.0.dev) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3) • Android SDK at /Users/developer/Library/Android/sdk • Platform android-30, build-tools 30.0.3 • Java binary at: /Applications/Android Studio 4.2 Preview.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6842174) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 13.0, Build version 13A5201i • CocoaPods version 1.10.2 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio • Android Studio at /Applications/Android Studio 4.2 Preview.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6842174) [!] Android Studio (version 2020.3) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart ✗ Unable to find bundled Java version. • Try updating or re-installing Android Studio. [✓] VS Code (version 1.59.0) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.25.0 [✓] Connected device (2 available) • iPhone (mobile) • XXXXXXXX-XXXXXXXXXXXXXXXX • ios • iOS 14.7.1 18G82 • Chrome (web) • chrome • web-javascript • Google Chrome 92.0.4515.131 ! Error: iPhone is busy: Fetching debug symbols for iPhone. Xcode will continue when iPhone is finished. (code -10) ! Doctor found issues in 1 category.
Unable to find bundled Java version.
が消えない。
developer@Mac-mini ~ % cd /Applications/Android\ Studio.app/Contents/jre developer@Mac-mini jre % ln -s ../jre jdk developer@Mac-mini jre % ln -s "/Library/Internet Plug-Ins/JavaAppletPlugin.plugin" jdk
とすると解消した。
developer@Mac-mini my_app_01 % flutter doctor -v [✓] Flutter (Channel master, 2.4.0-5.0.pre.166, on macOS 11.5.1 20G80 darwin-x64, locale ja-JP) • Flutter version 2.4.0-5.0.pre.166 at /Users/developer/Documents/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 2dc11a85ff (2 weeks ago), 2021-07-22 17:56:03 -0700 • Engine revision fbbb3b3f7b • Dart version 2.14.0 (build 2.14.0-343.0.dev) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3) • Android SDK at /Users/developer/Library/Android/sdk • Platform android-30, build-tools 30.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 13.0, Build version 13A5201i • CocoaPods version 1.10.2 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio • Android Studio at /Applications/Android Studio 4.2 Preview.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6842174) [✓] Android Studio (version 2020.3) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165) [✓] VS Code (version 1.59.0) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.25.0 [✓] Connected device (2 available) • iPhone (mobile) • XXXXXXXX-XXXXXXXXXXXXXXXX • ios • iOS 14.7.1 18G82 • Chrome (web) • chrome • web-javascript • Google Chrome 92.0.4515.131 ! Error: iPhone is busy: Fetching debug symbols for iPhone. Xcode will continue when iPhone is finished. (code -10) • No issues found!
No issues found!がやっと出た。