Flutter でセグメントを使った設定画面を作る

Flutter でセグメンテッドコントロールを使った設定画面のサンプルを作ったので紹介します。
flutter_advanced_segment を使います。
https://pub.dev/packages/flutter_advanced_segment

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/b50ae285-f8db-9eaa-f825-25f9b573c31f.png'  width='25%'>

# やること
1. セグメントを使う
2. 終了時に設定を保存する
3. 起動時に設定を読み込む

# ソースコード

- ファイル名：settings_page.dart
- クラス名：SettingsPage

```
  // 呼び出し側（ボタンなど）
  .....
  onPressed: () async {
    await Navigator.of(context).push(
      MaterialPageRoute(
        builder: (context) => SettingsPage(),
      )
    );
  }
```

```dart:settings_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_advanced_segment/flutter_advanced_segment.dart';
import 'package:shared_preferences/shared_preferences.dart';

class SettingsPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return SettingsPageState();
  }
}

class SettingsPageState extends State<SettingsPage> {
  AdvancedSegmentController _seg_value1;
  AdvancedSegmentController _seg_value2;

  Future<bool> load() async {
    final prefs = await SharedPreferences.getInstance();
    _seg_value1 = AdvancedSegmentController((prefs.getInt('value1') ?? 1).toString());
    _seg_value2 = AdvancedSegmentController((prefs.getInt('value2') ?? 2).toString());
    return true;
  }
  Future<bool> save() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setInt('value1', int.parse(_seg_value1.value));
    await prefs.setInt('value2', int.parse(_seg_value2.value));
    return true;
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      // 終了時に設定を保存する
      onWillPop: () {
        Navigator.of(context).pop(true);
        save();
        return Future.value(false);
      },
      // 起動時に設定を読み込む
      child: Scaffold(
        appBar: AppBar(title: Text('設定')),
        body: FutureBuilder(
        future: load(),
        builder: (context, snapshot) {
          if(snapshot.hasData == false)
            return SingleChildScrollView();
          return SingleChildScrollView(
            padding: EdgeInsets.symmetric(vertical: 50),
            child: Column(children: [
              MyLabel("解像度"),
              MySegment(
                controller: _seg_value1,
                segments: {
                  '1': '1920x1080',
                  '2': '1280x720',
                  '3': '640x360',
                },
              ),
              MyLabel("録画時間"),
              MySegment(
                controller: _seg_value2,
                segments: {
                  '1': '1時間',
                  '2': '2時間',
                  '3': '3時間',
                },
              ),
            ]),);})));
  }

  // 左寄せラベル
  Widget MyLabel(String label) {
    return Align(
      alignment: Alignment.centerLeft,
      child: Container(
        padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 20),
        child: Text(
          label,
          style: TextStyle(
            fontSize: 20,
            color: Colors.white,
          ),),),);
  }

  // 右寄せセグメント（内部で AdvancedSegment を使用）
  Widget MySegment({AdvancedSegmentController controller, Map<String, String> segments}) {
    return Align(
      alignment: Alignment.centerRight,
      child: Container(
        padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 20),
        child: AdvancedSegment(
          controller: controller,
          segments: segments,
          activeStyle: TextStyle(color: Colors.white),
          inactiveStyle: TextStyle(color: Colors.white),
          backgroundColor: Colors.black,
          sliderColor: Colors.blueAccent,
        )));}
}
```

# ポイント
1. AdvancedSegment を使う
AdvancedSegment を作成します。
引数の controller にはメンバ変数の _seg_value1 を渡します。
segments には値と表示用の文字を入れます。
タブを切り替えると同時にメンバ変数の _seg_value1 も変更されます。
あとはソースコードを頑張って見てください。

2. 終了時に設定を保存する
画面が終了した時に、設定値をアプリに保存します。

3. 起動時に設定を読み込む
Flutter 初心者の私はここで少しハマりました。
FutureBuilder で待たないと、設定値が読み込まれない状態で画面が起動してしまいました。

# まとめ
Flutter でセグメンテッドコントロールを使ってみました。
１回作れば簡単なので、このサンプルが役に立てば幸いです。
しっかし dart ってカッコ多すぎ。