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
88
Flutterハンズオン 4
Aya Ebata
September 09, 2024
Tweet
Share
More Decks by Aya Ebata
See All by Aya Ebata
Flutterハンズオン 5
aya_ebata
0
50
JEP 480: Structured Concurrency
aya_ebata
0
240
Flutterハンズオン 3
aya_ebata
0
48
Flutterハンズオン 2
aya_ebata
0
57
Flutterハンズオン 1
aya_ebata
0
88
あたらしい もじれつの かきかた
aya_ebata
0
99
社内勉強会vol.3@ごーふぁー荘
aya_ebata
0
750
社内勉強会vol.2@ごーふぁー荘
aya_ebata
1
750
社内勉強会vol.1@ごーふぁー荘
aya_ebata
0
700
Other Decks in Technology
See All in Technology
Operating Operator
shhnjk
1
600
いつの間にか入れ替わってる!?新しいAWS Security Hubとは?
cmusudakeisuke
0
140
【Oracle Cloud ウェビナー】インフラのプロフェッショナル集団KELが考えるOCIでのソリューション実現
oracle4engineer
PRO
1
100
改めてAWS WAFを振り返る~業務で使うためのポイント~
masakiokuda
2
270
Delegating the chores of authenticating users to Keycloak
ahus1
0
160
CDKTFについてざっくり理解する!!~CloudFormationからCDKTFへ変換するツールも作ってみた~
masakiokuda
1
170
fukabori.fm 出張版: 売上高617億円と高稼働率を陰で支えた社内ツール開発のあれこれ話 / 20250704 Yoshimasa Iwase & Tomoo Morikawa
shift_evolve
PRO
2
8k
React開発にStorybookとCopilotを導入して、爆速でUIを編集・確認する方法
yu_kod
1
290
VS CodeとGitHub Copilotで爆速開発!アップデートの波に乗るおさらい会 / Rapid Development with VS Code and GitHub Copilot: Catch the Latest Wave
yamachu
2
160
Delta airlines®️ USA Contact Numbers: Complete 2025 Support Guide
airtravelguide
0
340
Zero Data Loss Autonomous Recovery Service サービス概要
oracle4engineer
PRO
2
7.8k
AIの全社活用を推進するための安全なレールを敷いた話
shoheimitani
2
550
Featured
See All Featured
Faster Mobile Websites
deanohume
307
31k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
60k
Facilitating Awesome Meetings
lara
54
6.4k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
3.1k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
331
22k
Adopting Sorbet at Scale
ufuk
77
9.5k
The Invisible Side of Design
smashingmag
301
51k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
34
5.9k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.7k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
Building Applications with DynamoDB
mza
95
6.5k
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で簡単なアプリを作成した