.NET 開発基盤部会 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。

目次

概要

Flutter の step by step(其の一)。

手順1:インストールから実行まで。

コチラを参考にして実施

インストール

ダウンロード

https://flutter.dev/docs/get-started/install/windows

解凍&パス指定

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)

以下のCommandを実行し、TODOを確認する。

>flutter doctor

Android Studioのインストール

  • 既定値でインストール(Android Virtual Device(AVD)もインストール)。
  • 最後に、ライセンス条項に同意する。
    flutter doctor --android-licenses
  • 初期設定
    • 必要に応じて、Android Targetをインストール
    • 日本語化したら問題が出るらしい(現時点で解決しているか不明)。
  • ツール類
    %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%が展開されねぇんだけど...。

プラグインのインストール

「File」メニュー -> 「Settings..」 -> 「Plugins」

  • Flutterプラグインの「Install」ボタンを押下
  • Dartプラグインの「Install」ボタンを押下

チェック(2)

以下の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のパス変更

SDKのパスを変更する場合、以下の手順に従って変更する。

サンプルの生成と実行

新規作成プロジェクト

Android Studioで、新規作成プロジェクトする。

  • 「Start Flutter New Project」
    or 「File -> New -> New Flutter Project..」
  • 「Flutter Application」を選択
プロジェクトタイプ概要
Flutter Applicationアプリケーション用
Flutter Plugin AndroidネイティブAPI用ライブラリ用
Flutter Package画面部品用
Flutter ModuleDartライブラリ用
  • 以下を入力する。
    入力項目概要
    Project Nameプロジェクト名
    Flutter SDK path Project locationFlutter SDKをインストールしたフォルダを指定。
    Descriptionプロジェクト、アプリの説明
    Package Name通常、ドメインを反対にした値を入力

デバッグ実行

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

プロジェクトの開発

以降の手順で説明する。

デバッグ実行

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

エミュレータを登録して実行

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

実機でデバッグ実行する場合

  • IDEサポート
    最近の開発環境では、IDEサポートが追加されている。
  • マニュアル
    • 「Build」メニュー -> 「Flutter」 -> 「Build APK」
      を実行して、apkファイルをプロジェクト出力。
  • コチラの手順を参考にして、以下のフォルダのapkファイルを送り込む。
    %HOMEPATH%\AndroidStudioProjects\(flutter_app)\build\app\outputs\flutter-apk\app-release.apk
    ※ コマンドの実行に、PATH環境変数の設定は必須。

Flutter Devtoolsを利用する。

  • 「Tools」メニュー -> 「Flutter」 -> 「Open Flutter Devtools」を実行して、
  • デバッグ実行中に、[Flutter Inspector]のペインを開くとUI要素のツリーが表示される。
FlutterInspector
  • Flutter Devtoolsでは、その他、様々なツールを使用できる。
    • Timeline
    • Memory
    • Performance
    • Debugger
    • Logging

その他のツールを利用する。

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

手順2:イベントを実装する。

ボタンのWidget

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

RaisedButton?

  • onPressedに、任意のメソッドを書く。
  • deprecatedらしい→ElevatedButton
RaisedButton(
  child: const Text('Button'),
  color: Colors.orange,
  textColor: Colors.white,
  onPressed: () {},
),

ElevatedButton?

onPressedに、任意のメソッドを書く。

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

FlatButton?

  • onPressedに、任意のメソッドを書く。
  • deprecatedらしい→TextButton
FlatButton(
  child: const Text('Button'),
  textColor: Colors.black,
  onPressed: () {},
),

TextButton?

onPressedに、任意のメソッドを書く。

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

OutlineButton?

  • onPressedに、任意のメソッドを書く。
  • deprecatedらしい→OutlinedButton
OutlineButton(
  child: const Text('Button'),
  onPressed: () {},
),

OutlinedButton?

onPressedに、任意のメソッドを書く。

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

IconButton?

ButtonBar?

FloatingActionButton?

PopupMenuButton?

DropdownButton?

任意のWidget

ボタンでない、任意のWidgetに、イベントを実装できる。

InkWell?

簡単に、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?

InkWellのRipple エフェクトは無いが、
他のイベント(ジェスチャー)にも反応する。

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

参考

Qiita

手順3:画面遷移処理を実装する。

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

API

push

  • 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

  • 予め 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: ...);

メニュー

AppBar?

にNavigatorによる画面遷移を書く。

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

Drawer

  • 以下を参考に、ListTile?のonTap:にNavigatorによる画面遷移を書く。
  • MaterialPageRoute?のbuilderが返すWidgetにMyHomePage?を流用。

TabBar?

  • 以下は、TabPage?が遷移先で、Navigatorは使用しない。
  • _MyHomePageState?.buildメソッドが
    Scaffoldではなく、DefaultTabController?を返すのもポイント。

BottomNavigationBar?

  • 以下は、PageWidget?が遷移先で、Navigatorは使用しない。
  • bottomNavigationBar?のonTap:にIndex切替処理を書く。

参考

Qiita

手順4:レイアウトを行う。

body, children or childと、レイアウトを行う。

Layout系

Container

  • どちらも原点は”左上”
  • デフォルトで
    • Columnは縦方向いっぱい
    • Rowは横方向いっぱい

のサイズになる。

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

Center

  • 中央に寄るのはColmn(Row)自体。
  • 内部コンテンツの位置は変わらない。
body: Center(
  ...
  child: Column or Row

その他

  • Align
  • Padding
  • FittedBox? / BoxFit?
  • SafeArea?

Multi Layout系

Colmn

  • 列内の行は縦にスタック
  • 行内の内部コンテンツは横にスタック
body: Column(
  ...
  children: <Widget>[
    Row(

Row

  • 行内の列は横にスタック
  • 列内の内部コンテンツは縦にスタック
body: Row(
  ...
  children: <Widget>[
    Column(

その他

  • Expanded
  • Stack
  • ListView? / ListTile?
  • TabBar? / Tab / TabBarView?
  • BottomNavigationBar?

margin/padding

margin、paddingプロパティ

  • 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を指定

margin、paddingプロパティが無い場合

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

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

AxisAlignment?

内部コンテンツの位置

MainAxisAlignment?

  • 前述の、...の部分に、
    mainAxisAlignment: MainAxisAlignment.XXXXX,

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

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

CrossAxisAlignment?

  • 前述の、...の部分に、
    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>[
          ...,
        ],
      ),
    ),

参考

手順5:パッケージの追加と利用

english_wordsパッケージの例

パッケージの追加

english_wordsパッケージを追加・利用する。

  • パッケージを探す。
  • インストール方法は、
    dependencies:
      flutter:
        sdk: flutter
      english_words: ^4.0.0
  • その後、ツール・メニューかコマンドから、Pub Getを実行。
  • インストールされ、pubspec.lockにも記載が追加される。

パッケージの利用

  • インポートした上で
    import 'package:english_words/english_words.dart';
  • ライブラリを利用する(コチラのコードを修正)。
    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)

パッケージの追加

shared_preferencesパッケージを追加する必要がある。

パッケージの利用

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);
  });
}

参考

ブラウザ起動(url_launcher)

パッケージ追加

url_launcherパッケージを追加する必要がある。

パッケージの利用

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';
  }
}

参考

WebAPIを呼び出す。

パッケージ追加

HTTPパッケージを追加する必要がある。

GET

  • 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

  • 作法
    • 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。

その他

  • ヘッダ
    headersに、Map<String, String>型 の変数を指定する。
  • ...

参考

参考

Flutterのセカンド・ステップ

参考


添付ファイル: fileFlutterInspector.png 38件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2021-06-30 (水) 14:24:42 (33d)