Closed18

【Flutter編】Flutter入門してみた(作業ログ)

8rine238rine23

プロジェクトの作り方

  • 以下のコマンドを打って雛形を生成する
flutter create プロジェクト名
8rine238rine23

静的解析の設定方法

  • デフォルトでインストールされているflutter_lintsを使用する
  • 静的解析のオプションはanalysis_options.yamlで設定できる
8rine238rine23

Widget

  • UIを構築する上で必要になるクラス
  • UIに関する機能を提供するものやUI以外の機能(ナビゲーション)を提供するものもある
  • Flutterで予め用意されているWidgetやWidget同士を組み合わせた独自のWidgetを使ってUIを構築する
  • 独自のWidgetを作成する際にはStatelessWidgetStatefulWidgetのどちらかを継承する必要がある
8rine238rine23

MaterialApp

  • アプリケーションのテーマを決定したり、ページ遷移のためのNavigatorを構築する
class App extends StatelessWidget {
  const App({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    // 最初に表示するページとしてHomeScreen Widgetを指定
    return const MaterialApp(
      home: HomeScreen(),
    );
  }
}
8rine238rine23

Scaffold

  • ページを構成する際に便利なWidget
  • プロパティに表示したいWidgetを指定してあげることでUIの構築ができる
Scaffold(
  // 画面中央に「ホーム」という文字列を表示する
  body: Center(
    child: Text('ホーム'),
  ),
);
8rine238rine23

AppBar

  • 画面上部のヘッダを表示する際に使用するWidget
  • ScaffoldのappBarプロパティにこいつを指定して使う
  • 状態遷移後にもとの画面に戻るボタンが自動で追加されて便利
Scaffold(
  // ヘッダーに「ToDo」という文字列を表示させる
  appBar: AppBar(
    title: const Text('ToDo'),
  ),
  body: const Center(
    child: Text('ホーム'),
  ),
);
8rine238rine23

ListView.builder

  • リスト形式で表示する際に使用するWidget
  • 画面に表示したい要素の個数が多いときに名前付きコンストラクタ(builder)を使ってインスタンスを生成する
Scaffold(
  body: ListView.builder(
    // itemCountプロパティに指定された数だけListTileWidgetを表示する
    // indexは0からインクリメントされる
    itemBuilder: (context, index) => ListTile(
      title: Text(_todos[index]),
    ),
    itemCount: _todos.length,
  ),
);
8rine238rine23

ListTile

  • ListViewと併用して使えるWidget
  • プロパティで表示位置を指定できる(例:leading: 左端 title:leadingの右隣 trailing:右端)
8rine238rine23

FloatingActionButton

  • 画面上に浮かんでいるようなボタンを表示する際に使うWidget
  • ScaffoldのfloatingActionButtonプロパティにこいつを指定して使う
Scaffold(
  floatingActionButton: FloatingActionButton(
    // 十字に無印の背景のようなボタンを表示する
    child: const Icon(Icons.add),
    // ボタンが押されたら_todosに新しい要素を追加する
    onPressed: () {
      _todos.add('Todo ${_todos.length + 1}');
    },
  ),
);
8rine238rine23

画面に表示する要素に変更があったときにそれを画面に反映させるには?

  • StatefulWidgetを継承したWIdgetを使用して、反映させたい要素をsetStateで囲む
class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // 仮データ
  final _todos = List.generate(
    10,
    (index) => 'ToDo ${index + 1}',
  );

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.builder(
        itemBuilder: (context, index) => ListTile(
          title: Text(_todos[index]),
        ),
        itemCount: _todos.length,
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () {
          // setStateで囲まれた処理が実行されたら、自動的に画面が再構築される 
          setState(() {
            _todos.add('Todo ${_todos.length + 1}');
          });
        },
      ),
    );
  }
}
8rine238rine23

CheckboxListTile

  • 要素をリスト表示することに加えてチェックボックスも一緒に表示したいときに使用するWidget
  • onChangedプロパティでチェックのオンオフを実装できる
  • チェックのオンオフを画面に反映させたいときにはonChangedの中身をsetStateで囲む
class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // 仮データ
  final _todos = List.generate(
    10,
    (index) => ToDo(title: 'ToDo ${index + 1}'),
  );

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.builder(
        itemBuilder: (context, index) =>CheckboxListTile(
          // チェックボックスの状態が変化したら再描画
          onChanged: (checked) {
            setState(() {
             // チェック状態を反転させる
              _todos[index].archived = !_todos[index].archived;
            });
          },
         // チェックボックスの状態(onかoffか)
          value: _todos[index].archived,
          title: Text(_todos[index].title),
        ),
        itemCount: _todos.length,
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () {
          setState(() {
            _todos.add(ToDo(title: 'Todo ${_todos.length + 1}'),);
          });
        },
      ),
    );
  }
}
8rine238rine23

freezed

  • イミュータブル(変更不可能)なクラスを作成する際に使用するパッケージ
  • ミュータブルなクラスにメタデータとfactoryコンストラクタを加えてコードを生成する
  • 生成されたコードをpartで取り込むことで、変更差分のある新しいインスタンスを生成できるcopyWithが使えるようになる
8rine238rine23
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user.freezed.dart';


class User with _$User{
  factory ToDo({
    required String name,
    required String grade,
    (false) bool active,
  }) = _User;
}
8rine238rine23
  • 以下のコマンドを上のファイルがあるディレクトリで実行するとuser.freezed.dartが生成される
flutter pub run build_runner build
8rine238rine23
  • copyWithはこんなかんじに使う
void main(){
  final user_previous = User('alice', 'grade1');
  // user_previousのnameプロパティだけ変更したい
  final user_other = user_previous.copyWith(name: 'Bob');

  print(user_previous); // name:Alice grade:grade1 active:false
  print(user_other); // name:Bob grade:grade1 active:false
}
8rine238rine23

sembast

  • ローカルデータベースを使えるようにするパッケージ
  • NoSQLの一種で、json_serializableと相性が良い
  • path_providerパッケージのWidgetsFlutterBinding.ensureInitialized()を使ってアプリが利用できるパスを取得し、そこにデータベースのファイルを置く
  • 基本的にDB関係の処理は非同期で書く
8rine238rine23

初期化

final appDir = await getApplicationDocumentsDirectory();

// 利用できるパスにデータベースのファイルを作る
_database = await databaseFactoryIo.openDatabase(
      join(appDir.path, 'todo.db'),
);
_store = intMapStoreFactory.store('todo');

追加

// json形式に変換する
// 追加に成功したら、追加した予定に紐づくkeyが帰ってくる
final key = await _store.add(_database, todo.toJson());

更新

// keyを指定して更新
_store.record(key).put(_database, todo.toJson());

全件取得

final result = await _store.find( _database,finder: Finder(sortOrders: [SortOrder(Field.key, false)],),);
8rine238rine23

FutureBuilder

  • futureプロパティに指定した関数の返り値によって返すWidgetを変えることができる
  • builderプロパティはfutureの処理状態に応じて、指定された関数を複数回実行する
このスクラップは2022/09/18にクローズされました