<Flutter Dart>String interpolation(変数の文字列展開)
String interpolation(変数の文字列展開)
変数を文字列に展開
String name = 'Bob'; print('My name is $name'); // output // My name is Bob
変数をくくる
変数の後に続けてアルファベットを入力するとエラーとなる
String name = 'Bob'; print('My name is $nameA'); // output // Error: Undefined name 'nameA'. // print('My name is $nameA');
変数の後に続けてアルファベットを入力する場合は 変数名を中括弧「{」「}」で囲む。
String name = 'Bob'; print('My name is ${name}A'); // output // My name is BobA
文字列ないで変数の計算
文字列内でロジックを書く場合、
print('I am ${28 + 1} years old.'); // 変数は含めずにロジックを書くことができる int age = 27; print('I am ${age + 1} years old.'); // 変数を含めてロジックを書くことができる // output // I am 28 years old. // I am 29 years old.
パッケージの導入時のpubspec.yamlの書き方
はじめに
パッケージ導入する時にはpubspec.yamlのdependencyに追記します。 pub.devから取得する以外にも方法があります。 その方法をメモしておきます。
- pub.devからパッケージ取得
- gitのリポジトリからパッケージ取得
- ローカルからパッケージ取得
例
riverpodの取得を例にします。
pub.devからパッケージ取得
dependencies: riverpod: ^2.3.6
gitのリポジトリからパッケージ取得
dependencies: riverpod: git: url: https://github.com/rrousselGit/riverpod.git path: packages/riverpod
ローカルからパッケージ取得
下記のpathにgithubからriverpodを取得しておきます。 その上で下記の通り記載します
dependencies: riverpod: path: /Users/example/Git/riverpod/packages/riverpod
最後に
詳しく知りたい場合はこちらを参照
アプリのアイコン画像を設定する
はじめに
アプリをリリースしようとするときに必要になります。 個人的にはリリース前でもアイコンを設定しておくとモチベーションがあがります。
手順
アイコン画像(1024px)は既にある前提です。 用意してあるアイコン画像をプロジェクト配下のフォルダに保存しておきます。 下記手順ではassets/icon/icon.pngに保存している前提です。
その前提で下記の手順が必要となります。
- flutter_launcher_iconsのパッケージ導入
- pubspec.ymlに設定
- アイコン作成処理実行
1. flutter_launcher_iconsのパッケージ導入
こちらがパッケージの公式ページです。
flutter_launcher_icons | Dart Package
pubspec.ymlのdev_dependenciesにflutter_launcher_iconsの行を追加し、 flutter pub getコマンドでパッケージ取得します。
dev_dependencies: flutter_launcher_icons: "^0.13.1" # 追加
2. pubspec.ymlに設定
flutter_launcher_icons: android: true ios: true remove_alpha_ios: true # アイコン画像にアルファが設定されている場合に追加 image_path: "assets/icon/icon.png" # 素材のアイコン画像が保存されているパス
3. アイコン作成処理実行
下記コマンド実行します。 アプリに必要な各種サイズのアイコン画像が作成され、iOSやAndroidのプロジェクトにアイコンが設定されます。 実行後、アプリをビルドしてアイコン画像が設定されていることを確認します。
dart run flutter_launcher_icons
MaterialApp.routerのrouterConfig
はじめに
画面遷移でgo_routerを使っていて、initialLocationを設定しても効いていないことがあった。 原因はMaterialApp.routerの引数にrouteInformationProviderをセットし忘れていたからだった。
原因を調べていたときにFlutter公式では下記のようにrouterConfigに GoRouterオブジェクトをセットしていて、routerDelegateやrouteInformationParserなどを使っていない。
MaterialApp.router( routerConfig: GoRouter( // … ) );
画面遷移でgo_routerを使い始めたときにはなかった方法 or 勉強に利用したサイトがそういうやりかたをしていたのだろう。 routerDelegateやrouteInformationParserなどをセットしなくてもいいやり方があるのかと思い、 routerConfigについて少し調べたのでそのメモを残す。
RouterConfigについて
RouterConfigの定義は下記のとおり。
/// A convenient bundle to configure a [Router] widget. /// /// To configure a [Router] widget, one needs to provide several delegates, /// [RouteInformationProvider], [RouteInformationParser], [RouterDelegate], /// and [BackButtonDispatcher]. This abstract class provides way to bundle these /// delegates into a single object to configure a [Router]. /// /// The [routerDelegate] must not be null. The [backButtonDispatcher], /// [routeInformationProvider], and [routeInformationProvider] are optional. /// /// The [routeInformationProvider] and [routeInformationParser] must /// both be provided or not provided. class RouterConfig<T> { /// Creates a [RouterConfig]. /// /// The [routerDelegate] must not be null. The [backButtonDispatcher], /// [routeInformationProvider], and [routeInformationParser] are optional. /// /// The [routeInformationProvider] and [routeInformationParser] must /// both be provided or not provided. const RouterConfig({ this.routeInformationProvider, this.routeInformationParser, required this.routerDelegate, this.backButtonDispatcher, }) : assert((routeInformationProvider == null) == (routeInformationParser == null)); /// The [RouteInformationProvider] that is used to configure the [Router]. final RouteInformationProvider? routeInformationProvider; /// The [RouteInformationParser] that is used to configure the [Router]. final RouteInformationParser<T>? routeInformationParser; /// The [RouterDelegate] that is used to configure the [Router]. final RouterDelegate<T> routerDelegate; /// The [BackButtonDispatcher] that is used to configure the [Router]. final BackButtonDispatcher? backButtonDispatcher; }
A convenient bundle to configure a [Router] widget.
コメントの一文が示している通り、まとめて設定してくれる。 まとめて設定してくれる対象は下記のとおりでした。
- routerDelegate
- backButtonDispatcher
- routeInformationProvider
- routeInformationProvider
セグメントボタン(SegmentedButton)を使った実装
はじめに
セグメントボタンの使い道としては 複数の選択肢から選択し、
- ビューを切り替える
- ソート順を切り替える
など、が挙げられます。
SegmentedButtonクラス
# コンストラクタ SegmentedButton({ Key? key, required List<ButtonSegment<T>> segments, required Set<T> selected, void onSelectionChanged(Set<T>)?, bool multiSelectionEnabled = false, bool emptySelectionAllowed = false, ButtonStyle? style, bool showSelectedIcon = true, Widget? selectedIcon })
- segmentsが選択肢です
- segmentsの各要素であるButtonSegmentのvalueが選択されたときに取得できる値です
- onSelectionChangedが選択されたときに実行される処理です
実装例
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'SegmentedButton', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(), ); } } class MyHomePage extends StatelessWidget { const MyHomePage({Key? key}): super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('SegmentedButton'), ), body: Container( color: Colors.grey, child: Center( child: SegmentedButton( segments: const <ButtonSegment<int>>[ ButtonSegment( value: 0, label: Padding( padding: EdgeInsets.all(4.0), child: Text('年'), ), ), ButtonSegment( value: 1, label: Text('月'), ), ], selected: const <int>{ 0 }, onSelectionChanged: (Set<int> newSelection) => print('$newSelection'), ), ), ) ); } }
公式ドキュメント
iOSのWireless debugging(Wifi経由での実機デバッグ)
はじめに
実機で動かすとモチベーションがあがるタイプです。 ときどきケーブルが無くて、仕方なくシミュレータでデバッグしてました。 Flutter3.10.0でWifi経由で実機にアプリ転送し、デバッグできるようになったようです。
iOSのWireless debugging設定
Flutter3.10.0以上でないとできないので、FlutterがFlutter3.10.0以上であることを確認しましょう。 そして、「1. iOS端末へのアプリ転送設定」はケーブルを使った有線であっても必要になる設定です。すでに設定済みであればスキップして「2. Wireless debugging設定」をします。これでWifi経由で実機でデバッグできるようになりました!
1. iOS端末へのアプリ転送設定
- 開発MacとiOS端末をケーブルでつなぐ
- もしiOS16以上であれば、設定アプリの「プライバシーとセキュリティ」のデベロッパーモードをオンにする
- 開発中のFlutterアプリのRunner.xcworkspaceをXcodeで開く
- Signing & Capabilities > Teamでアカウントを設定する
- automatically manage signingにチェックが入っていない場合は、General > Identity > Bundle Identifierを設定する
- Xcodeで設定したiOS端末を選択してアプリ起動する or flutter runする
2. Wireless debugging設定
- 開発MacとiOS端末で同じWifiネットワークにつなぐ
- 開発中のFlutterアプリのRunner.xcworkspaceをXcodeで開く
- Xcodeを起動し、上部バーからXcode > Window > Devices and Simulatorsを開く。
- 接続しているiOS端末を探し、「Connect via Network」にチェックを入れる。しばらく処理中のプログレスが出ることがあるが終わったらケーブルをはずしても大丈夫です
Argumentsを開く
- IPv4ネットワークの場合、--vm-service-host=0.0.0.0を追加(IPv6の場合は--vm-service-host=::0)をArguments Passed On Launchに追加する
- Xcodeで設定したiOS端末を選択してアプリ起動する or flutter runする
[Flutter]Dart3で追加されたClass Modifier
はじめに
Google I/O 2023でDart3のリリースが報告されました。 Dart3でClass Modifierが追加されたので試してみました。 (Class Modifierとは、抽象Classの頭につけているabstractなどです)
interfaceクラス
// vehicle.dart interface class Vehicle { void drive() { print('drive'); } }
このVehicleクラスが定義されたファイルとは別ファイルで使う場合に下記の特長があります。
- インスタンス化できる
- 継承できない
- implementsできる
// car.dart import 'vehicle.dart'; // インスタンス化できる final myCar = Vehicle(); // 継承できない(エラーになる) class Car extends Vehicle { String name; Car({ required this.name, }) : super(); } // implementsできる class Truck implements Vehicle { String name; Truck({ required this.name, }) : super(); @override void drive() { print('drive truck'); } }
baseクラス
// vehicle.dart base class Vehicle { void drive() { print('drive'); } }
このVehicleクラスが定義されたファイルとは別ファイルで使う場合に下記の特長があります。
- インスタンス化できる
- 継承できる。ただし、base or finalのクラスに限る
- implementsできない
// car.dart import 'vehicle.dart'; // インスタンス化できる final myCar = Vehicle(); // 継承できる。base or finalでなければならない base class Car extends Vehicle { String name; Car({ required this.name, }) : super(); } final class Bus extends Vehicle { } // implementsできない base class Truck implements Vehicle { String name; Truck({ required this.name, }) : super(); @override void drive() { print('drive truck'); } }
finalクラス
// vehicle.dart final class Vehicle { void drive() { print('drive'); } }
このVehicleクラスが定義されたファイルとは別ファイルで使う場合に下記の特長があります。
- インスタンス化できる
- 継承できない
- implementsできない
// car.dart import 'vehicle.dart'; // インスタンス化できる final myCar = Vehicle(); // 継承できない base class Car extends Vehicle { String name; Car({ required this.name, }) : super(); } // implementsできない base class Truck implements Vehicle { String name; Truck({ required this.name, }) : super(); @override void drive() { print('drive truck'); } }