Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Flutterハンズオン 4
Search
Aya Ebata
September 09, 2024
Technology
0
70
Flutterハンズオン 4
Aya Ebata
September 09, 2024
Tweet
Share
More Decks by Aya Ebata
See All by Aya Ebata
Flutterハンズオン 5
aya_ebata
0
37
JEP 480: Structured Concurrency
aya_ebata
0
220
Flutterハンズオン 3
aya_ebata
0
38
Flutterハンズオン 2
aya_ebata
0
49
Flutterハンズオン 1
aya_ebata
0
77
あたらしい もじれつの かきかた
aya_ebata
0
94
社内勉強会vol.3@ごーふぁー荘
aya_ebata
0
720
社内勉強会vol.2@ごーふぁー荘
aya_ebata
1
730
社内勉強会vol.1@ごーふぁー荘
aya_ebata
0
680
Other Decks in Technology
See All in Technology
30代からでも遅くない! 内製開発の世界に飛び込み、最前線で戦うLLMアプリ開発エンジニアになろう
minorun365
PRO
16
5k
もう難しくない!誰でもカンタンDocker入門 〜30分であなたのPCにアプリを立ち上げる〜
devops_vtj
0
180
2025-04-24 "Manga AI Understanding & Localization" Furukawa Arata (CyberAgent, Inc)
ornew
2
320
AIとSREで「今」できること
honmarkhunt
3
680
Perl歴約10年のエンジニアがフルスタックTypeScriptに出会ってみた
papix
1
250
AIでめっちゃ便利になったけど、結局みんなで学ぶよねっていう話
kakehashi
PRO
1
520
2025-04-14 Data & Analytics 井戸端会議 Multi tenant log platform with Iceberg
kamijin_fanta
0
170
Compose におけるパスワード自動入力とパスワード保存
tonionagauzzi
0
190
3D生成AIのための画像生成
kosukeito
2
580
製造業向けIoTソリューション提案資料.pdf
haruki_uiru
0
130
持続可能なドキュメント運用のリアル: 1年間の成果とこれから
akitok_
1
270
Simplify! 10 ways to reduce complexity in software development
ufried
1
180
Featured
See All Featured
Optimising Largest Contentful Paint
csswizardry
37
3.2k
BBQ
matthewcrist
88
9.6k
Designing Experiences People Love
moore
142
24k
Code Review Best Practice
trishagee
67
18k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
14
1.4k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
29
1.7k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
23
2.7k
KATA
mclloyd
29
14k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
251
21k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
119
51k
Mobile First: as difficult as doing things right
swwweet
223
9.6k
Making the Leap to Tech Lead
cromwellryan
133
9.2k
Transcript
Flutterハンズオン 4 2024/09/10 社内勉強会 えばた あや
今日話すこと 1. VSCodeでFlutterプロジェクトを開始する 2. Flutterの基礎
1. VSCodeでFlutterプロジェクトを 開始する
VSCodeでFlutterプロジェクトを開始する 0. VSCodeを開く - 以下のコマンドと同様なことをVSCodeでやっていきます $ flutter create [プロジェクト名]
VSCodeでFlutterプロジェクトを開始する 1. コマンドパレットを開き、[Flutter: New Project]を検索し選択する
VSCodeでFlutterプロジェクトを開始する 2. [Application]を選択し、プロジェクトを作成するフォルダを選択する
VSCodeでFlutterプロジェクトを開始する 3. スネークケースでプロジェクトに名前を付ける
VSCodeでFlutterプロジェクトを開始する 4. iOSのシミュレータ/Androidの エミュレータを開いて、 VSCodeでデバイスの選択を して、実行できることを確認 する
VSCodeでFlutterプロジェクトを開始する ※ たまにデバイスの選択が反映されないことがあるので、その場合は コマンドパレットで[Developer: Reload Window]を実行
VSCodeでFlutterプロジェクトを開始する 5. 前回同様、カウンターアプリが表示されれば成功
2. Flutterの基礎
Flutterの基礎 本日はこちらを元にやっていきます! https://docs.flutter.dev/ui
Hello World!を出力する 1. カウンターアプリの実装を削除する - MyAppクラスのbuild()メソッドの中身を全部削除する - その下にあるクラスも消しちゃってOK
Hello World!を出力する 2. MyAppクラスのbuild()メソッドに以下を貼り付ける return const Center( child: Text( 'Hello,
world!', textDirection: TextDirection.ltr, ), );
Hello World!を出力する 3. 保存をすると、ホットリロードが走って反映される!
Hello World!を出力する 解説 import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); }
class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const Center( child: Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ); } }
Hello World!を出力する 解説 - マテリアルデザインのFlutter開発で必要なものが入っている packageをインポートする import 'package:flutter/material.dart';
Hello World!を出力する 解説 - runApp()でアプリを開始する - runApp()の中に直接CenterやTextなどのウィジェットを書く のではなく、クラスを呼ぶようにする -> 直接書くとホットリロードが効かないよ! void
main() { runApp(const MyApp()); }
Hello World!を出力する 解説 - StatelessWidgetを継承する - 状態を持たないウィジェットであることを意味する - 状態を持つ場合はStatefulWidgetを使用する class MyApp
extends StatelessWidget { // ... }
Hello World!を出力する 解説 - buildメソッドにウィジェットの実装を書いていく @override Widget build(BuildContext context) { //
... }
Hello World!を出力する 解説 - Center: 中央に表示する - child: センターにするウィジェットを指定する - Text:
文字列を表示する - textDirection: テキストの開始位置(今回は左を指定) return const Center( child: Text('Hello, world!', textDirection: TextDirection.ltr), );
その他のよく使うウィジェット - Row: 水平方向のレイアウトを作成する ※ Centerウィジェットのchildを以下に変更 Row( textDirection: TextDirection.ltr, mainAxisSize:
MainAxisSize.min, children: [ Text('Hello, world!1', textDirection: TextDirection.ltr), Text('Hello, world!2', textDirection: TextDirection.ltr), ], ),
その他のよく使うウィジェット - Row: 水平方向のレイアウトを作成する 以下が出力される
その他のよく使うウィジェット - Column: 垂直方向のレイアウトを作成する ※ MyAppクラスのbuildメソッドのreturnに以下を追加 const Column( mainAxisAlignment: MainAxisAlignment.center,
children: [ Text('Hello, world!1', textDirection: TextDirection.ltr), Text('Hello, world!2', textDirection: TextDirection.ltr), ], );
その他のよく使うウィジェット - Column: 垂直方向のレイアウトを作成する 以下が出力される
その他のよく使うウィジェット - Stack: レイアウトを重ねて配置する ※ MyAppクラスのbuildメソッドのreturnに以下を追加 const Center( child: Stack(
textDirection: TextDirection.ltr, children: [ Text('Hello, world!1', textDirection: TextDirection.ltr), Text('Hello, world!2', textDirection: TextDirection.ltr), ], ), );
その他のよく使うウィジェット - Stack: レイアウトを重ねて配置する 以下が出力される(1と2の文字が重なってる)
その他のよく使うウィジェット - Container: 箱のウィジェットが作成できる ※ MyAppクラスのbuildメソッドのreturnに以下を追加 Center( child: Container( color:
Colors.blue, width: 100, height: 100, ), );
その他のよく使うウィジェット - Container: 箱のウィジェットが作成できる 以下が出力される
テーマを反映させる - mainのrunApp()にMaterialAppを追加する - 上層部にウィジェットを追加するにはcommand+.でwrapできる - テーマの設定、ルートの管理、ローカライゼーションなどが できるようになる void main()
{ runApp(const MaterialApp(title: 'Flutter Tutorial', home: MyApp())); }
テーマを反映させる - MyAppクラスのbuildメソッドにScaffoldを追加する - Material Designの基本的なビジュアルレイアウト構造を提供する @override Widget build(BuildContext context)
{ return const Scaffold( body: Center( child: Text('Hello World!'), ), ); }
テーマを反映させる - テーマが反映されたことを確認
AppBarを追加する - ScaffoldにappBarを追加する - constをScaffoldからCenterに書き換える(余計な再描画を防ぐため) @override Widget build(BuildContext context) {
return const Scaffold( appBar: AppBar(title: const Text('Example title')), body: const Center(child: Text('Hello World!')), ); }
AppBarを追加する - AppBarが反映されたことを確認
ハンバーガーメニューを追加する - AppBarの引数に以下を追加 leading: const IconButton( icon: Icon(Icons.menu), tooltip: 'Navigation
menu', onPressed: null, ),
ハンバーガーメニューを追加する - ハンバーガーメニューが反映されたことを 確認
検索アイコンを追加する - AppBarの引数に以下を追加 actions: const [ IconButton( icon: Icon(Icons.search), tooltip:
'Search', onPressed: null, ), ],
検索アイコンを追加する - 検索アイコンが反映されたことを確認
フローティングアクションボタンを追加する - Scaffoldの引数に以下を追加 floatingActionButton: const FloatingActionButton( tooltip: 'Add', onPressed: null,
child: Icon(Icons.add), ),
フローティングアクションボタンを追加する - フローティングアクションボタンが 反映されたことを確認
インクリメントできるボタンを追加する - 以下のようなものを追加していきます
インクリメントできるボタンを追加する - Scaffoldのbodyにある「Hello World!」を出力するテキストをColumn ウィジェットでwrapする -> 垂直方向にウィジェットを追加できるようになる Column( mainAxisAlignment: MainAxisAlignment.center,
children: [ Text('Hello World!'), ], ),
インクリメントできるボタンを追加する - ボタンとテキストが横並びのウィジェットを作りたいのでRowを追加 body: const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center,
children: [ Text('Hello World!'), Row(mainAxisAlignment: MainAxisAlignment.center, children: []), ], ), ),
インクリメントできるボタンを追加する - Rowのchildrenにボタンを追加 Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed:
null, // TODO: 後で実装する child: Text('Increment'), ), ], ),
インクリメントできるボタンを追加する - Rowの中にテキストも追加 Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton(onPressed: null,
child: Text('Increment')), Text('Count: 0'), ], ),
インクリメントできるボタンを追加する - ボタンとテキストの間を少し開ける Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton(onPressed: null,
child: Text('Increment')), SizedBox(width: 16), Text('Count: 0'), ], ),
インクリメントできるボタンを追加する 1. ElevatedButtonのonPressedを空の無名関数に置き換える 2. ElevatedButtonが定数ではなくなるのでbody直後のconstを削除 3. その代わり、TextとSizedBoxにconstを追加 ElevatedButton( onPressed: ()
{ // TODO: 後で実装する }, child: const Text('Increment'), ),
状態(state)管理を用意する - インクリメントのための状態管理を用意する(以下現状) class MyApp extends StatelessWidget { const MyApp({super.key});
@override Widget build(BuildContext context) { // ... } }
状態(state)管理を用意する - MyAppを_MyAppStateに変更し、State<MyApp>を継承する - コンストラクタはここではいらなくなる class _MyAppState extends State<MyApp> {
@override Widget build(BuildContext context) { // ... } }
状態(state)管理を用意する - MyAppクラスをまた新しく追加する - 状態を扱うのでStatefulWidgetを継承する - ここでコンストラクタの定義をする class MyApp extends
StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); }
状態(state)管理を用意する - _MyAppStateクラスに以下の状態を追加する int _counter = 0; void _increment() {
setState(() { _counter++; }); }
状態(state)管理を適用する - ElevatedButtonに先ほど定義した_increment()メソッドを指定する ElevatedButton( onPressed: _increment, child: const Text('Increment'), ),
状態(state)管理を適用する - Textに先ほど定義した_counter変数を指定する - _counter変数の値は動的に変化する値になるのでconstを削除する ElevatedButton( onPressed: _increment, child: const
Text('Count: $_counter'), ),
状態(state)管理を適用する - Incrementボタンをクリックして カウントアップされることを確認 する
リファクタリングする - Countのテキストを別ウィジェットに切り出すために、 CounterDisplayクラスを用意する class CounterDisplay extends StatelessWidget { const
CounterDisplay({super.key}); @override Widget build(BuildContext context) { return const Text('Count: x'); // いったん仮の値 } }
リファクタリングする - CounterDisplayウィジェットを呼び出すように変更する Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton(onPressed: _increment,
child: const Text('Increment')), const SizedBox(width: 16), const CounterDisplay(), ], ),
リファクタリングする - _counterの値を使うために、CounterDisplayクラスに値をcount という名前で渡すように変更する // コンストラクタにthis.countを追加 const CounterDisplay({required this.count, super.key});
// countプロパティを追加 final int count;
リファクタリングする - CounterDisplayクラスのbuildメソッドにてcountを表示する - 動的な値になるのでTextについていたconstは削除する @override Widget build(BuildContext context) {
return const Text('Count: $count'); }
リファクタリングする - CounterDisplayの呼び出し部分に_counterを渡す - こちらも動的な値を扱うため、CounterDisplayの前のconstを削除する const CounterDisplay(count: _counter)
リファクタリングする ※ command+. -> Extract Widget -> CounterDisplayを入力でも作成できる
リファクタリングする 練習問題 1. IncrementボタンをCounterIncrementorクラスに切り出す - voidのメソッドを渡すための型はVoidCallbackです 2. 作成したCounterIncrementorウィジェットを使ってIncrementボタン を呼び出して表示する 3. カウントアップができることを確認する
リファクタリングする 練習問題 解答例 class CounterIncrementor extends StatelessWidget { const CounterIncrementor({required this.onPressed, super.key});
final VoidCallback onPressed; @override Widget build(BuildContext context) { return ElevatedButton( onPressed: onPressed, child: const Text('Increment'), ); } }
リファクタリングする 練習問題 解答例 Row( mainAxisAlignment: MainAxisAlignment.center, children: [ CounterIncrementor(onPressed: _increment), const SizedBox(width:
16), CounterDisplay(count: _counter), ], ),
リファクタリングする 練習問題 解答例 ※ 状態管理しているメソッドを渡している場合はExtract Widgetをすると 怒られるので、一旦空の無名関数を渡してあげると出来るようになる
まとめ - VSCodeでFlutterアプリを新規作成する方法を学んだ - Flutterで簡単なアプリを作成した