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
85
Flutterハンズオン 4
Aya Ebata
September 09, 2024
Tweet
Share
More Decks by Aya Ebata
See All by Aya Ebata
Flutterハンズオン 5
aya_ebata
0
49
JEP 480: Structured Concurrency
aya_ebata
0
240
Flutterハンズオン 3
aya_ebata
0
47
Flutterハンズオン 2
aya_ebata
0
55
Flutterハンズオン 1
aya_ebata
0
85
あたらしい もじれつの かきかた
aya_ebata
0
98
社内勉強会vol.3@ごーふぁー荘
aya_ebata
0
740
社内勉強会vol.2@ごーふぁー荘
aya_ebata
1
750
社内勉強会vol.1@ごーふぁー荘
aya_ebata
0
690
Other Decks in Technology
See All in Technology
地図も、未来も、オープンに。 〜OSGeo.JPとFOSS4Gのご紹介〜
wata909
0
110
Model Mondays S2E02: Model Context Protocol
nitya
0
220
VISITS_AIIoTビジネス共創ラボ登壇資料.pdf
iotcomjpadmin
0
160
Clineを含めたAIエージェントを 大規模組織に導入し、投資対効果を考える / Introducing AI agents into your organization
i35_267
4
1.6k
Observability infrastructure behind the trillion-messages scale Kafka platform
lycorptech_jp
PRO
0
140
Prox Industries株式会社 会社紹介資料
proxindustries
0
280
SalesforceArchitectGroupOsaka#20_CNX'25_Report
atomica7sei
0
150
セキュリティの民主化は何故必要なのか_AWS WAF 運用の 10 の苦悩から学ぶ
yoh
1
110
Definition of Done
kawaguti
PRO
6
480
Javaで作る RAGを活用した Q&Aアプリケーション
recruitengineers
PRO
1
110
製造業からパッケージ製品まで、あらゆる領域をカバー!生成AIを利用したテストシナリオ生成 / 20250627 Suguru Ishii
shift_evolve
PRO
1
140
低レイヤを知りたいPHPerのためのCコンパイラ作成入門 完全版 / Building a C Compiler for PHPers Who Want to Dive into Low-Level Programming - Expanded
tomzoh
4
3.2k
Featured
See All Featured
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.3k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
281
13k
Making the Leap to Tech Lead
cromwellryan
134
9.3k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Adopting Sorbet at Scale
ufuk
77
9.4k
Designing for humans not robots
tammielis
253
25k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.2k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
44
2.4k
How to Think Like a Performance Engineer
csswizardry
24
1.7k
Code Reviewing Like a Champion
maltzj
524
40k
Building Flexible Design Systems
yeseniaperezcruz
328
39k
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で簡単なアプリを作成した