5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ネイティブあまり経験ないけどFlutterがそれなりに使えるまで

Last updated at Posted at 2020-07-21

ネイティブは年単位での経験が有るわけではなく、フロントエンドとバックエンドをメインで経験しています。そんな中でFlutterをそれなりに使えるようになるまで残したメモをまとめています。

ホットリロードとDartのおかげで、
個人的には「これ、ネイティブ・・?」と錯覚するほどフロントエンドっぽさを感じました。

※なにか変な部分や間違いが有りましたらご指摘いただけると幸いです!

環境構築

エディタは何を使えばいいんだろう?

個人的にはVSCodeがなれていたのでそちらで開発していましたが、やりたいなと思ったことは今のところできています。

環境構築する

公式のget-started通りにやればokです(丸投げだけど本当に思っていたよりかなり楽に構築できます)。
途中なにかが不足している場合などでも、flutter doctorコマンドで環境構築完了に何が足りないかわかるのがとてもありがたい。

参考: https://flutter.dev/docs/get-started/install

ビルドする

ネイティブ経験がそれほどなかったので、「え、ビルド、大変そう・・」と思ったのですがかんたんでした。

シミュレータかmacにつなげた実機か、どのデバイスにビルドするか選択してビルドします。
実機の場合は少し設定が必要があるかと思うので「ios実機ビルドできない」の項目を下記参照ください。

コマンドの場合

$ flutter devices
---
2 connected devices:
hogePhone         • XXXXXXXXXXXXXXXXXxx            • ios • iOS 13.4.1
iPhone 11 Pro Max • XXXXXXXXXXXXXXXXXxx            • ios •

$ flutter run -d {device_id}

VSCodeでビルドする場合

スクリーンショット 2020-07-21 11.36.13.png

vscodeの画面右下にビルド対象が表示されているので対象にしたい端末を設定します。

よく使ったコマンド

$ flutter create {app_name}

# pubspec.yamlを更新したときパッケージを取得(基本エディタで保存したときに自動で取得される)
$ flutter pub get

# ビルド
$ flutter run
$ flutter run -d {device_id} # デバイスを指定してビルド

# deviceIdを列挙
$ flutter devices
-----------------
2 connected devices:
hogePhone             • 00008030-001838320CF2802E            • ios • iOS 13.4.1
iPhone 11 Pro Max • 9A5B8A02-0CE1-4955-9450-B787F6BAD274 • ios •

packageの追加

pubspec.yamlに追加したいpackageを追記して保存 -> 自動でinstallが始まる

dependencies:
  flutter:
    sdk: flutter
  http: ^0.12.1 # ←

HotReloadとHotRestart

HotReload

エディタでビルドを実行した場合は保存した際にホットリロードされますが、
ターミナルの方で flutter runでビルドした場合、
コマンドでrをいちいち入力しないとホットリロードされません。(ほんとに?!)

$ flutter run
....
Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.

HotRestart

コンパイルエラーやアプリが落ちた場合やパッケージ追加時・フォントの変更など、ホットリロードしても変更が反映されないケース(下記参考に詳細)があります。なので、更新されないなぁという時はホットリスタートを行う必要があります。(それでも変更されないケースがあるのでその時はアプリ再起動)

下記はVSCodeのデバッグUI。緑の矢印がhot-restart
vscode.png

参考: https://flutter.dev/docs/development/tools/hot-reload#special-cases![uploading-0]()

自動フォーマット

VSCodeの場合settings.jsonに下記追加
フォーマットはされるけど変なフォーマットされるなぁと言う時は、大体,が無い。
自分は一行にまとめたいケースなどではあえて,を省略したりしていました。

"editor.formatOnSave": true,

状態管理

自分は一番これに時間を費やしてしまいました。
setState, BLoC, Provider, Reduxなど、状態管理のやりかたが色いろあるようで、ちょこちょこ変わっているそうです。
僕はめんどくさがりなので、今後メインになりそうな手法をとりあえず選びたい・・と思っているものの

“What toppings should I get on my pizza?”
参考: https://blog.codemagic.io/flutter-tutorial-pros-and-cons-of-state-management-approaches/

みたいなもんだと書いてあるとおりどれがいいっていうのはまだ明確にはなっていないそう。。 

というのを横目で見つつgoogleとしては、特にこだわりが無ければProviderを推すということなのでProviderを使ってみることにしました。

Providerで状態管理

テキストで実装の流れを書くと下記のような感じ

  1. rootにしたいwidgetにChangeNotifierProvider でwidgetをwrapする
  2. Providerには状態と各methodをもたせる
  3. rootに設定したtree内でProviderを参照できる
main.dart

import 'package:provider/provider.dart';
import './providers/counter.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext ctx) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (ctx) => Counter()),
        // 複数設置できる
      ],
      ...
provider/counter.dart
import 'package:provider/provider.dart';

class Counter with ChangeNotifier {
  int count = 0;

  void add() {
    count++;
    notifyListeners();  // これでproviderに更新を伝える
  }
}
CounterScreen.dart
class CounterScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counter = Provider.of<Counter>(context); // CounterのProviderを参照
    return Column(
          children: <Widget>[
            Center(child: Text(counter.count)), // Providerに持たせている状態を参照
            FlatButton(
             onPressed: () => counter.add(), // Providerが持っているmethodを呼び出す
             child: Text('Plus One'),
            ),
         ],
      }),
    );
  }
}

REST-APIを使う

まずモデルを作成する

class AlbumModel {
  final int userId;
  final int id;
  final String title;

  AlbumModel({this.userId, this.id, this.title});

  factory AlbumModel.fromJson(Map<String, dynamic> json) {
    return AlbumModel(
      userId: json['userId'],
      id: json['id'],
      title: json['title'],
    );
  }
}

そのModelを使ってapiを叩いていく

GET

Future<AlbumModel> fetchAlbum() async {
  String url = 'https://jsonplaceholder.typicode.com/albums/2';
  
  final response = await http.get(url);
  if(response.statusCode == 200) {
    return AlbumModel.fromJson(json.decode(response.body));
  } else {
    throw Exception('Failed to load album');
  }
}

POST

Future<AlbumModel> createAlbum(String title) async {
  String url = 'https://jsonplaceholder.typicode.com/albums';
  final http.Response response = await http.post(
    url,
    headers: <String, String> {
      'Content-Type': 'application/json; charset=UTF-8',
    },
    body: jsonEncode(<String, String>{
      'title': title,
    })
  );

  if (response.statusCode == 201) {
    return AlbumModel.fromJson(json.decode(response.body));
  } else {
    throw Exception('Failed to load album.');
  }
}
5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?