「[[.NET 開発基盤部会 Wiki>http://dotnetdevelopmentinfrastructure.osscons.jp]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。

-[[戻る>Flutter]]
--Flutterのファースト・ステップ
--[[Flutterのセカンド・ステップ]]
--[[Flutterのサード・ステップ]]
--[[Flutterの4thステップ]]
--[[Flutterの5thステップ]]

*目次 [#l34bf167]
#contents

*概要 [#rde47fa2]
[[Flutter]] の step by step(其の一)。

*手順1:インストールから実行まで。 [#sdd49677]
[[コチラ>Flutter#a9ed99c8]]を参考にして実施

**インストール [#e5336e5a]

***ダウンロード [#r9e85d44]
https://flutter.dev/docs/get-started/install/windows

***解凍&パス指定 [#pda245ef]
flutter_windows_x.x.x-stable.zip

-解凍
 C:\prog\dev\flutter
-パス指定
 // ユーザーの環境変数に設定する例
 $path =[System.Environment]::GetEnvironmentVariable('PATH','User')
 $path +=";" + "C:\prog\dev\flutter\bin";
 [System.Environment]::SetEnvironmentVariable('PATH',$path,'User')

***チェック(1) [#h3bd155b]
以下のCommandを実行し、TODOを確認する。
 >flutter doctor

***[[Android Studioのインストール>Android Studio#a4e75be5]] [#qc322227]
-既定値でインストール(Android Virtual Device(AVD)もインストール)。

-最後に、ライセンス条項に同意する。
 flutter doctor --android-licenses

-[[初期設定>Android Studio#yfcbb29e]]
--必要に応じて、Android Targetをインストール
--日本語化したら問題が出るらしい(現時点で解決しているか不明)。

-[[PATH環境変数>Android Studio#f38ea058]]

--ツール類
 %USERPROFILE%\AppData\Local\Android\Sdk\tools
 %USERPROFILE%\AppData\Local\Android\Sdk\tools\bin
 %USERPROFILE%\AppData\Local\Android\Sdk\platform-tools

--gradleのbin~
 %USERPROFILE%\.gradle\wrapper\dists\gradle-6.7-all\cuy9mc7upwgwgeb72wkcrupxe\gradle-6.7\bin

>※ 前述のPowerShellだと、%USERPROFILE%が展開されねぇんだけど...。

***プラグインのインストール [#of1de50d]
「File」メニュー -> 「Settings..」 -> 「Plugins」
-Flutterプラグインの「Install」ボタンを押下
-Dartプラグインの「Install」ボタンを押下

***チェック(2) [#h3bd155b]
以下のCommandを実行し、問題が無いことを確認する。

 >flutter doctor
 Doctor summary (to see all details, run flutter doctor -v):
 [√] Flutter (Channel stable, 2.0.3, on Microsoft Windows [Version 
 10.0.19041.867], locale ja-JP)
 [√] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
 [√] Chrome - develop for the web
 [√] Android Studio (version 4.1.0)
 [√] VS Code, 64-bit edition (version 1.47.2)
 [√] Connected device (2 available)
 
 • No issues found!
 
 >

***余談:SDKのパス変更 [#lbb2ae25]
SDKのパスを変更する場合、以下の手順に従って変更する。

-Flutter SDKのPathを変えた時にやること【Flutter】 - Qiita~
https://qiita.com/umi_mori/items/46073f5bfb88348efd16

**サンプルの生成と実行 [#p6672f41]

***新規作成プロジェクト [#ab55e378]
[[Android Studio>#qc322227]]で、新規作成プロジェクトする。

-「Start Flutter New Project」~
or 「File -> New -> New Flutter Project..」

-「Flutter Application」を選択

|プロジェクトタイプ|概要|h
|Flutter Application|アプリケーション用|
|Flutter Plugin Android|ネイティブAPI用ライブラリ用|
|Flutter Package|画面部品用|
|Flutter Module|Dartライブラリ用|

-以下を入力する。
|入力項目|概要|h
|Project Name|プロジェクト名|
|Flutter SDK path Project location|Flutter SDKをインストールしたフォルダを指定。|
|Description|プロジェクト、アプリの説明|
|Package Name|通常、ドメインを反対にした値を入力|

-[[コチラ>Flutter#zb4ac86e]]のコードが生成される。

***デバッグ実行 [#n16190b8]
-実行するデバイスでChromeなどのブラウザを選択し、
-緑三角(実行)、虫(デバッグ)ボタンを押すと実行。
-ブラウザではなく、エミュレータや実機を使う手順は[[コチラ>#re710153]]。

***プロジェクトの開発 [#fe5f689f]
以降の手順で説明する。

**デバッグ実行 [#re710153]
[[Android Studio>#ab55e378]]で1GB、[[エミュレータ>#qef3780a]]で6GB程、メモリを消費するので、~
開発機のメモリが16GB程度では少々、スペック不足、故に[[実機でのデバッグ>#ud190db6]]を行うことになる。

***エミュレータを登録して実行 [#qef3780a]
-必要に応じて、[[Windows ハイパーバイザー プラットフォーム>Androidのエミュレータ#pfe59a21]]を有効化しておく。~
(コレにより、Hyper-V、Docker for Windows、WSL2との同居が可能に)

-[[コチラ>Androidのエミュレータ#s9f7ba94]]の新し目の手順になる。

--エミュレータの登録
---「Tools」メニュー -> 「AVD Manager」
---(「Create Virtual Device ..」でデバイスを選択し「Next」ボタンを押下)
---(API Levelを選択(最新に近いモノを選択する))
---「Actions」から三角ボタンを押して、エミュレータを起動

--エミュレータでデバッグ実行
---実行するデバイスを選択し、
---緑三角(実行)、虫(デバッグ)ボタンを押すと実行。

***実機でデバッグ実行する場合 [#ud190db6]
-[[IDEサポート>Flutter - ビルドとデプロイ#wf653b03]]~
最近の開発環境では、IDEサポートが追加されている。

-マニュアル
--「Build」メニュー -> 「Flutter」 -> 「Build APK」~
を実行して、apkファイルをプロジェクト出力。

--[[コチラ>Androidのデプロイ#o1221b8b]]の手順を参考にして、以下のフォルダのapkファイルを送り込む。
 %HOMEPATH%\AndroidStudioProjects\(flutter_app)\build\app\outputs\flutter-apk\app-release.apk
※ コマンドの実行に、[[PATH環境変数の設定>#qc322227]]は必須。

***Flutter Devtoolsを利用する。 [#i45db2b6]
-「Tools」メニュー -> 「Flutter」 -> 「Open Flutter Devtools」を実行して、
-デバッグ実行中に、[Flutter Inspector]のペインを開くとUI要素のツリーが表示される。

#ref(FlutterInspector.png,left,nowrap,FlutterInspector,75%)

-Flutter Devtoolsでは、その他、様々なツールを使用できる。
--Timeline
--Memory
--Performance
--Debugger
--Logging

***その他のツールを利用する。 [#m0d93c29]
-外部デザイナとして、Flutter Studioがある。~
--AppBuilder 2~
https://flutterstudio.app/

-加えて、
--[[Flutter Inspector>#i45db2b6]]と、
--Widget等の追加、削除+Hot Reload

>を併用すると、RAD風に開発できる。

-参考
--開発効率が上がるFlutter x Android StudioのTips集 - Qiita~
https://qiita.com/akatsuki174/items/d66fa84fe51aa2d9a1a6

*手順2:イベントを実装する。 [#jf1cdd07]

**ボタンのWidget [#m8b57d15]
-以下のようなボタンがある。
-「() {}」(空のラムダ式)を、~
生成されたコード中にある、~
「_incrementCounter」に変更してテスト可能。

***RaisedButton [#e36807a9]
-onPressedに、任意のメソッドを書く。
-deprecatedらしい→[[ElevatedButton>#f894aa5a]]

 RaisedButton(
   child: const Text('Button'),
   color: Colors.orange,
   textColor: Colors.white,
   onPressed: () {},
 ),

***ElevatedButton [#f894aa5a]
onPressedに、任意のメソッドを書く。

 ElevatedButton(
   child: const Text('Button'),
   style: ElevatedButton.styleFrom(
     primary: Colors.orange,
     onPrimary: Colors.white,
   ),
   onPressed: () {},
 ),

***FlatButton [#z69dde61]
-onPressedに、任意のメソッドを書く。
-deprecatedらしい→[[TextButton>#wa77bfd4]]

 FlatButton(
   child: const Text('Button'),
   textColor: Colors.black,
   onPressed: () {},
 ),

***TextButton [#wa77bfd4]
onPressedに、任意のメソッドを書く。

 TextButton(
   child: const Text('Button'),
   style: TextButton.styleFrom(
     primary: Colors.black,
   ),
   onPressed: () {},
 ),

***OutlineButton [#vf4dde96]
-onPressedに、任意のメソッドを書く。
-deprecatedらしい→[[OutlinedButton>#tdfd2905]]

 OutlineButton(
   child: const Text('Button'),
   onPressed: () {},
 ),

***OutlinedButton [#tdfd2905]
onPressedに、任意のメソッドを書く。

 OutlinedButton(
   child: const Text('Button'),
   style: OutlinedButton.styleFrom(
     primary: Colors.black,
   ),
   onPressed: () {},
 ),

***IconButton [#daa818af]

***ButtonBar [#ncee4c62]

***FloatingActionButton [#x2287a59]

***PopupMenuButton [#v437fd5e]

***DropdownButton [#mbd05014]

-参考
--【Flutter】ドロップダウンボタンを表示する | スクリプちん~
https://dtpscriptin.com/flutter-dropdownbutton/
--Flutterで2つのDropdownButtonを使う - Qiita~
https://qiita.com/bigface00/items/c0fad7b0e94869d1c609

**任意のWidget [#n5395d65]
[[ボタン>#m8b57d15]]でない、任意のWidgetに、イベントを実装できる。

***InkWell [#cbab219c]
簡単に、Ripple エフェクトを付ける事が出来る。

 Material(                  // 親にMaterialが必須
  color: Colors.blue,       // Material自体は青を指定
  child: Center(            //
    child: Ink(             // ここをContainerにするとsplashが効かないので、Inkに変える
      color: Colors.yellow, // 背景色はここで指定
      width: 200.0,
      height: 100.0,
      child: InkWell(
          onTap: () {},
          child: Center(child: Text('YELLOW'))
      ),
    ),
  ),
 )

***GestureDetector [#ta864cd4]
[[InkWell>#cbab219c]]のRipple エフェクトは無いが、~
他のイベント(ジェスチャー)にも反応する。

 GestureDetector(
   // タッチ検出対象のWidget
   child: Text(
     'How to use GestureDetector',
     textAlign: TextAlign.center,
     overflow: TextOverflow.ellipsis,
     style: TextStyle(fontWeight: FontWeight.bold),
   ),
   // ダブルタップ
   onDoubleTap: _incrementCounter
 )

**参考 [#c9d61f89]
-[Flutter]コピペで使える!ボタンのデザイン16種類をまとめました~
https://zenn.dev/coka01/articles/cb0b632766138e9858e7
-Flutter: InkWell vs GestureDetector: what is the difference? - Stack Overflow~
https://stackoverflow.com/questions/56725308/flutter-inkwell-vs-gesturedetector-what-is-the-difference

***Qiita [#r7419f30]
-Flutter:Widget一覧 > Material Components > Buttons~
https://qiita.com/matsukatsu/items/e289e30231fffb1e4502#buttons
-Flutter でよく使う(と思う)コードまとめ > イベント~
https://qiita.com/chooyan_eng/items/e7f1fcca1eeb0cf150b5

*手順3:画面遷移処理を実装する。 [#y1c65c17]
-画面遷移の実装について。
-MaterialApp以下で実装。
--MaterialApp が持っている Navigator を使って画面遷移。
--Navigatorの動作イメージはStackで、一番上の Route が現在の画面。
---無限にPushできてしまうので、実装を考える必要がある。
---常にPoP & Pushだと、戻った時に、常に状態は保存されていない。
---...

**API [#r068b122]

***push [#ve163562]
-Widget を MaterialPageRoute に渡して Route を作る。

-Navigator.pushにRouteを渡して画面遷移。

 Navigator.of(context).pop();
 Navigator.of(context).push(
   MaterialPageRoute(
     builder: (context) {
       return MyHomePage(title: 'Flutter Demo Home PageA');
     },
   ),
 );

***pushNamed [#l7e321b0]
-予め MaterialApp に Routes を登録しておく。
 Widget build(BuildContext context) {
   return MaterialApp(
     title: 'Flutter Demo',
     theme: ThemeData(
      ...
     ),
     routes: {
       '/': (context) => MyHomePage(title: 'Flutter Demo Home Page'),
       '/message': (context) => MessageView(),

-Navigator.pushNamedにルート名を渡して画面遷移。

--
 Navigator.of(context).pushNamed("/message");

--
 Navigator.pushNamed(context, '/message', arguments: ...);

**メニュー [#ab032765]

***AppBar [#uab4869a]
-以下を参考に、AppBarのactions:
--[[IconButton>#daa818af]]のonPressed:
--[[PopupMenuButton>#v437fd5e]]のonSelected:

>にNavigatorによる[[画面遷移>#y1c65c17]]を書く。

-MaterialPageRouteのbuilderが返すWidgetにMyHomePageを流用。

-参考
--AppBar | Flutter Doc JP~
https://flutter.ctrnost.com/basic/navigation/appbar/

***Drawer [#a39c49ff]
-以下を参考に、ListTileのonTap:にNavigatorによる[[画面遷移>#y1c65c17]]を書く。
-MaterialPageRouteのbuilderが返すWidgetにMyHomePageを流用。

-参考
--Drawer | Flutter Doc JP~
https://flutter.ctrnost.com/basic/navigation/drawer/
--Flutterでdrawerを利用した遷移時にdrawerを閉じる方法 - Qiita~
https://qiita.com/hiko1129/items/9d31938046bbf4dcad2e

***TabBar [#nb84e642]
-以下は、TabPageが遷移先で、Navigatorは使用しない。
-_MyHomePageState.buildメソッドが~
Scaffoldではなく、DefaultTabControllerを返すのもポイント。

-参考
--TabBar | Flutter Doc JP~
https://flutter.ctrnost.com/basic/navigation/tabbar/

***BottomNavigationBar [#md88c7f0]
-以下は、PageWidgetが遷移先で、Navigatorは使用しない。
-bottomNavigationBarのonTap:にIndex切替処理を書く。

-参考
--BottomNavigationBar | Flutter Doc JP~
https://flutter.ctrnost.com/basic/navigation/bottomnavigationbar/

**参考 [#sefba61b]
-ナビゲーション | Flutter Doc JP~
https://flutter.ctrnost.com/basic/navigation/

-FlutterのNavigationとRoutingを理解する~
https://itome.team/blog/2019/12/flutter-advent-calendar-day10/

***Qiita [#p8ca044b]
-Flutter でよく使う(と思う)コードまとめ > 画面遷移~
https://qiita.com/chooyan_eng/items/e7f1fcca1eeb0cf150b5
-[Flutter]画面遷移のやり方~
https://qiita.com/kono-hiroki/items/b1a8f19dfab371e7816d

*手順4:レイアウトを行う。 [#gb136ec0]
body, children or childと、レイアウトを行う。

**Layout系 [#k8fee006]

***Container [#r1745fe6]
-どちらも原点は”左上”

-デフォルトで
--Columnは縦方向いっぱい
--Rowは横方向いっぱい

>のサイズになる。

 body: Container(
   ...
   child: Column or Row

***Center [#dc1ee6cd]
-中央に寄るのはColmn(Row)自体。
-内部コンテンツの位置は変わらない。

 body: Center(
   ...
   child: Column or Row

***その他 [#j25f12b4]
-Align
-Padding
-FittedBox / BoxFit
-SafeArea

**Multi Layout系 [#lcc20e22]

***Colmn [#f3227fa2]
-列内の行は縦にスタック
-行内の内部コンテンツは横にスタック

 body: Column(
   ...
   children: <Widget>[
     Row(

***Row [#s89c6bd9]
-行内の列は横にスタック
-列内の内部コンテンツは縦にスタック

 body: Row(
   ...
   children: <Widget>[
     Column(

***その他 [#ydacbb99]
-Expanded
-Stack
-ListView / ListTile
-TabBar / Tab / TabBarView
-BottomNavigationBar

**margin/padding [#u24eb54f]

***margin、paddingプロパティ [#u8ce80ee]
-childプロパティのあるWidgetの、~
margin、paddingプロパティにEdgeInsetsを指定する。
 margin: EdgeInsets.only(top: 100),
 padding: EdgeInsets.only(top: 50),

-EdgeInsetsには以下のメソッドがある。
--only:上下左右のmargin/paddingを指定
--fromLTRB:onlyの名前無し引数版(上下左右)
--symmetric:縦方向横方向のmargin/paddingを指定
--all:全方向のmargin/paddingを指定

-参考
--【Flutter】Containerのmarginの設定方法~
EdgeInsetsをざっくりまとめる | tty×Dev~
https://ttydev.com/2020/11/11/flutter-edgeinsets/

***margin、paddingプロパティが無い場合 [#nb407d63]
RowやColumnなど、childrenプロパティのあるWidgetは、~
margin、paddingプロパティを持たないが、~
Containerをネストして使用すると面倒なので、~
SizedBoxを拡張したSpaceBoxを使用すると良い。

-参考
--Padding(またはMargin)だけが目的でContainerを~
使うのは間違ってる(というか分かりづらい) -Flutter-~

**AxisAlignment [#j3887756]
内部コンテンツの位置

***MainAxisAlignment [#jd40a297]
-前述の、...の部分に、
 mainAxisAlignment: MainAxisAlignment.XXXXX,

>...と書き、主軸方向の配置位置を調整する。

--start/end~
先頭/末尾寄せ
--center~
中央寄せ
--spaceEvenly~
間隔を均等に配置
--spaceAround~
各余白を均等に配置
--spaceBetween~
最大限に分散配置

***CrossAxisAlignment [#v5b164d4]
-前述の、...の部分に、
 crossAxisAlignment: CrossAxisAlignment.XXXXX,

>...と書き、交差軸方向の配置位置を調整する。

--start/end~
先頭/末尾寄せ
--center~
中央寄せ
--stretch~
引き伸ばして配置
--baseline~
ベースラインを揃えて配置

-SizedBox.expand~
交差軸方向のスペースをすべて取らない場合、~
CrossAxisAlignmentが適切に機能しない事がある。~
この場合は、SizedBox.expandで、スペースを消費させる。
 body: SizedBox.expand(
   child: Column(
     mainAxisAlignment: MainAxisAlignment.center,
     crossAxisAlignment: CrossAxisAlignment.center,
     children: <Widget>[
       ...,
     ],
   ),
 ),

**参考 [#g0352efc]
-Flutter基礎 – Column/Rowの色々な並べ方 | UKI-HOME~
https://uki-home.xyz/2020/03/30/2052/

*手順5:パッケージの追加と利用 [#wdf201cb]

**english_wordsパッケージの例 [#c2f39d2c]

***パッケージの追加 [#l4895405]
english_wordsパッケージを追加・利用する。

-パッケージを探す。

--サイトで、english_wordsを探す。~
https://pub.dev/flutter/packages

--探したら、~
https://pub.dev/packages/english_words
---評価を確認して、~
https://pub.dev/packages/english_words/score
---インストール方法を確認する。~
https://pub.dev/packages/english_words/install

-インストール方法は、
 dependencies:
   flutter:
     sdk: flutter
   english_words: ^4.0.0

--その後、ツール・メニューかコマンドから、Pub Getを実行。

--インストールされ、pubspec.lockにも記載が追加される。

***パッケージの利用 [#l994c979]
-インポートした上で
 import 'package:english_words/english_words.dart';

-ライブラリを利用する([[コチラ>#ab55e378]]のコードを修正)。
 class _MyHomePageState extends State<MyHomePage> {
   String _counter = 'hoge';
 
   void _incrementCounter() {
     setState(() {
       // This call to setState tells the Flutter framework that something has
       // changed in this State, which causes it to rerun the build method below
       // so that the display can reflect the updated values. If we changed
       // _counter without calling setState(), then the build method would not be
       // called again, and so nothing would appear to happen.
       _counter = WordPair.random().asPascalCase;
     });
   }

**データの永続化(shared_preferences) [#k0d2f689]

***パッケージの追加 [#y2248706]
shared_preferencesパッケージを追加する必要がある。

-shared_preferences| Flutter Package~
https://pub.dev/packages/shared_preferences/install
 dependencies:
   flutter:
     sdk: flutter
   shared_preferences: ^2.0.6

***パッケージの利用 [#j552eb54]
 import 'package:shared_preferences/shared_preferences.dart';
 
 Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
 late Future<int> _counter;
 
 Future<void> _incrementCounter() async {
   final SharedPreferences prefs = await _prefs;
   final int counter = (prefs.getInt('counter') ?? 0) + 1;
   setState(() {
     _counter = prefs.setInt("counter", counter).then((bool success) {
       return counter;
     });
   });
 }
 
 @override
 void initState() {
   super.initState();
   _counter = _prefs.then((SharedPreferences prefs) {
     return (prefs.getInt('counter') ?? 0);
   });
 }


***参考 [#sefa34d2]
-Flutterでshared_preferencesを使う - Qiita~
https://qiita.com/fukuit/items/0f385dde916cd7668c72

**ブラウザ起動(url_launcher) [#y663789f]

***パッケージ追加 [#s4421c50]
url_launcher[[パッケージを追加する必要がある。>Flutterのファースト・ステップ#wdf201cb]]
url_launcherパッケージを追加する必要がある。

-url_launcher | Flutter Package~
https://pub.dev/packages/url_launcher/install
 dependencies:
   flutter:
     sdk: flutter
   url_launcher: ^6.0.4

***パッケージの利用 [#rcd57bc6]
 import 'package:url_launcher/url_launcher.dart';

 _launchURL() async {
   const url = "http://https://www.google.co.jp/";
   if (await canLaunch(url)) {
     await launch(url);
   } else {
     throw 'Could not Launch $url';
   }
 }

***参考 [#l6c52f19]
-Flutterで外部ブラウザに遷移する - Qiita~
https://qiita.com/superman9387/items/868ce6ad60b3c177bff1

**WebAPIを呼び出す。 [#k0b7d0c5]

***パッケージ追加 [#ea0f55f3]
HTTP[[パッケージを追加する必要がある。>#wdf201cb]]
HTTPパッケージを追加する必要がある。

-http | Dart Package~
https://pub.dev/packages/http/install
 import 'package:http/http.dart';

***GET [#r32f0dbd]
-Example~
https://pub.dev/packages/http/example
  import 'dart:convert' as convert;
  import 'package:http/http.dart' as http;
 
  // This example uses the Google Books API to search for books about http.
  // https://developers.google.com/books/docs/overview
  var url =
      Uri.https('www.googleapis.com', '/books/v1/volumes', {'q': '{http}'});
 
  // Await the http get response, then decode the json-formatted response.
  var response = await http.get(url);
  if (response.statusCode == 200) {
    var jsonResponse =
        convert.jsonDecode(response.body) as Map<String, dynamic>;
    var itemCount = jsonResponse['totalItems'];
    print('Number of books about http: $itemCount.');
  } else {
    print('Request failed with status: ${response.statusCode}.');
  }
-作法
--Futureのメソッドチェーン
 void sendRequest() {
   http
     .get(url)
     .then((response) {
       print(response);
     })
     .catchError((error) => print(error));
 }

--async/await
 Future<void> sendRequest() async {
   try {
     final response = await http.get(url);
     print(response);
   } on Exception caach (error) {
     print(error);
   }
 }

***POST [#sef9e1b2]
-作法
--Futureのメソッドチェーン
 ...

--async/await
 var response = await http.post(
     "https://www.example.com/path/to/api",
     body: {
         "nickname": "chooyan",
         "description": "A freelance mobile app developer",
     },
 );

-コンテンツ

--application/x-www-form-urlencoded~
bodyに、Map<String, String>型 の変数を指定する。

--application/json
---JSON形式のString型を指定する。
---json.encode(Map<String, String>型)でもOK。

***その他 [#vdc68763]
-ヘッダ~
headersに、Map<String, String>型 の変数を指定する。

-...

***参考 [#q5bd47cb]
-dart - Flutter http headers - Stack Overflow~
https://stackoverflow.com/questions/53299447/flutter-http-headers

-Make authenticated requests - Flutter~
https://flutter.dev/docs/cookbook/networking/authenticated-requests

-Google Books API からJSONデータを取得してjQueryで処理する - Qiita~
https://dishware.sakura.ne.jp/swift/archives/129

**参考 [#a16079da]
-Page 1 | Top Flutter packages~
https://pub.dev/flutter/packages

-外部パッケージ | Flutter Doc JP~
https://flutter.ctrnost.com/tutorial/tutorial04/
-【Flutter】パッケージ導入手順 - Qiita~
https://qiita.com/akeome/items/0a6ebf3af402fdf62c79

*[[Flutterのセカンド・ステップ]] [#r39843fc]

*[[参考>Flutter#a9ed99c8]] [#i485f5b3]

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS