Closed25

Flutter の Cupertino Widgets を使ってみる

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

Counter

https://api.flutter.dev/flutter/cupertino/CupertinoPageScaffold-class.html

Flutter のカウンターアプリを Material → Cupertino にする

準備コマンド

プロジェクトの作り方は Material の場合と同じ

flutter create hello_cupertino
cd hello_cupertino

追加のパッケージのインストールなども必要ない

コード

全体的に変更する必要がある

hello_cupertino/lib/main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(
        brightness: Brightness.light,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text(widget.title),
        trailing: CupertinoButton(
          onPressed: _incrementCounter,
          child: const Icon(CupertinoIcons.add),
        ),
      ),
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text('$_counter'),
          ],
        ),
      ),
    );
  }
}

実行コマンド

flutter run

実行結果

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoActionSheet

https://api.flutter.dev/flutter/cupertino/CupertinoActionSheet-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const CupertinoApp(
    home: MyApp(),
    theme: CupertinoThemeData(brightness: Brightness.light),
  ));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoButton(
          onPressed: () => _showActionSheet(context),
          child: const Text('Show acton sheet'),
        ),
      ),
    );
  }

  Future<void> _showActionSheet(BuildContext context) async {
    final result = await showCupertinoModalPopup<String>(
      context: context,
      builder: (context) {
        return CupertinoActionSheet(
          title: const Text('Title'),
          message: const Text('Message'),
          actions: <CupertinoActionSheetAction>[
            CupertinoActionSheetAction(
              onPressed: () {
                Navigator.of(context).pop("result");
              },
              child: const Text('Action'),
            ),
          ],
        );
      },
    );

    print(result);
  }
}

実行結果

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoActivityIndicator

https://api.flutter.dev/flutter/cupertino/CupertinoActivityIndicator-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const CupertinoApp(
    home: MyApp(),
    theme: CupertinoThemeData(brightness: Brightness.light),
  ));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoActivityIndicator(),
      ),
    );
  }
}

実行結果

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoAlertDialog

https://api.flutter.dev/flutter/cupertino/CupertinoAlertDialog-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const CupertinoApp(
    home: MyApp(),
    theme: CupertinoThemeData(brightness: Brightness.light),
  ));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoButton(
          child: const Text("Show dialog"),
          onPressed: () async {
            final answer = await showCupertinoModalPopup<String>(
              context: context,
              builder: (context) {
                return CupertinoAlertDialog(
                  title: const Text('title'),
                  content: const Text('content'),
                  actions: <CupertinoDialogAction>[
                    CupertinoDialogAction(
                      onPressed: () {
                        Navigator.of(context).pop("no");
                      },
                      isDefaultAction: true,
                      child: const Text('No'),
                    ),
                    CupertinoDialogAction(
                      onPressed: () {
                        Navigator.of(context).pop("yes");
                      },
                      child: const Text('Yes'),
                    ),
                  ],
                );
              },
            );

            print(answer);
          },
        ),
      ),
    );
  }
}

実行結果

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoButton

https://api.flutter.dev/flutter/cupertino/CupertinoButton-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const CupertinoApp(
    home: MyApp(),
    theme: CupertinoThemeData(brightness: Brightness.light),
  ));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            CupertinoButton(onPressed: () {}, child: const Text('Enabled')),
            const SizedBox(height: 15),
            const CupertinoButton(onPressed: null, child: Text('Disabled')),
            const SizedBox(height: 15),
            CupertinoButton.filled(onPressed: () {}, child: const Text('Enabled')),
            const SizedBox(height: 15),
            const CupertinoButton.filled(onPressed: null, child: Text('Disabled')),
          ],
        ),
      ),
    );
  }
}

実行結果

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoContextMenu

https://api.flutter.dev/flutter/cupertino/CupertinoContextMenu-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(
        brightness: Brightness.light,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoContextMenu(
          actions: [
            CupertinoContextMenuAction(
              onPressed: () {},
              child: const Text('Action'),
            ),
          ],
          child: Container(
            color: CupertinoColors.activeBlue,
            width: 100,
            height: 100,
            alignment: Alignment.center,
            child: const Text('Text'),
          ),
        ),
      ),
    );
  }
}

実行結果

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoDatePicker

https://api.flutter.dev/flutter/cupertino/CupertinoDatePicker-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(
        brightness: Brightness.light,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoButton.filled(
          onPressed: () {
            showCupertinoModalPopup(
              context: context,
              builder: (context) {
                return Container(
                  height: 216,
                  color: CupertinoColors.systemBackground.resolveFrom(context),
                  child: SafeArea(
                    child: CupertinoDatePicker(
                      onDateTimeChanged: (value) {},
                    ),
                  ),
                );
              },
            );
          },
          child: const Text('Show date picker'),
        ),
      ),
    );
  }
}

実行結果

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoNavigationBar

https://api.flutter.dev/flutter/cupertino/CupertinoNavigationBar-class.html

コード

MaterialApp でも CupertinoNavigationBar は使える

タイトルを中央に配置したい時に便利

main.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('AppBar title')),
      body: Column(
        children: [
          CupertinoNavigationBar(
            leading: OutlinedButton(
              onPressed: () {},
              child: const Text('Button'),
            ),
            middle: const Text('Title'),
          ),
        ],
      ),
    );
  }
}

実行結果

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoPicker

https://api.flutter.dev/flutter/cupertino/CupertinoPicker-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoButton(
          onPressed: () {
            showCupertinoModalPopup(
              context: context,
              builder: (context) {
                return Container(
                  height: 216,
                  color: CupertinoColors.systemBackground.resolveFrom(context),
                  child: SafeArea(
                    child: CupertinoPicker(
                      itemExtent: 32,
                      onSelectedItemChanged: (value) {},
                      children: List.generate(3, (index) => const Text('Item')),
                    ),
                  ),
                );
              },
            );
          },
          child: const Text('Show picker'),
        ),
      ),
    );
  }
}

実行結果

メモ

SafeArea って何だろうと思って調べたらわかりやすい記事があった

https://zenn.dev/captain_blue/articles/introduce-sarearea-in-flutter

iPhone 画面の上端や下端にあるものを上手に避けてくれるらしい

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoPopupSurface

https://api.flutter.dev/flutter/cupertino/CupertinoPopupSurface-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoButton(
          onPressed: () {
            showCupertinoModalPopup(
              context: context,
              builder: (context) {
                return CupertinoPopupSurface(
                  child: Container(
                    height: 200,
                    color: CupertinoColors.systemBackground.resolveFrom(context),
                    child: Center(
                      child: CupertinoButton(
                        onPressed: () {
                          Navigator.of(context).pop();
                        },
                        child: const Text('Close'),
                      ),
                    ),
                  ),
                );
              },
            );
          },
          child: const Text('Show picker'),
        ),
      ),
    );
  }
}

実行結果

メモ

実装手順の素晴らしい動画を見つけた

https://www.youtube.com/watch?v=aJgYmAyzVqo

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoScrollbar

https://api.flutter.dev/flutter/cupertino/CupertinoScrollbar-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final ScrollController _scrollController = ScrollController();

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: CupertinoScrollbar(
        thumbVisibility: true,
        controller: _scrollController,
        child: ListView.builder(
          controller: _scrollController,
          itemCount: 100,
          itemBuilder: (context, index) {
            return const Padding(
              padding: EdgeInsets.all(10),
              child: Text('Title'),
            );
          },
        ),
      ),
    );
  }
}

実行結果

メモ

ScrollController を Scrollbar と ListView の両方に設定しないとエラーになる

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoSearchTextField

https://api.flutter.dev/flutter/cupertino/CupertinoSearchTextField-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoSearchTextField(),
      ),
    );
  }
}

実行結果

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoSegmentedControl

https://api.flutter.dev/flutter/cupertino/CupertinoSegmentedControl-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoSegmentedControl<String>(
          onValueChanged: (value) {
            
          },
          children: {
            for (final segment in ["1", "2", "3"])
              segment: Padding(
                padding: const EdgeInsets.all(10),
                child: Text(segment),
              ),
          },
        ),
      ),
    );
  }
}

実行結果

メモ

実際に使う場合は StatefulWidget, setState, groupValue を使う

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoSlider

https://api.flutter.dev/flutter/cupertino/CupertinoSlider-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  double slider = 1;

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoSlider(
          min: 0,
          max: 10,
          value: slider,
          onChanged: (value) {
            setState(() {
              slider = value;
            });
          },
        ),
      ),
    );
  }
}

実行結果

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoSlidingSegmentedControl

https://api.flutter.dev/flutter/cupertino/CupertinoSlidingSegmentedControl-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _segment = "1";

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoSlidingSegmentedControl<String>(
          groupValue: _segment,
          onValueChanged: (value) {
            setState(() {
              _segment = value!;
            });
          },
          children: {
            for (final segment in ["1", "2", "3"])
              segment: Padding(
                padding: const EdgeInsets.all(10),
                child: Text(segment),
              ),
          },
        ),
      ),
    );
  }
}

実行結果

メモ

CupertinoSegmentedControl とほぼ同じ

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoSliverNavigationBar

https://api.flutter.dev/flutter/cupertino/CupertinoSliverNavigationBar-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoPageScaffold(
      child: CustomScrollView(
        slivers: [
          CupertinoSliverNavigationBar(
            leading: Icon(CupertinoIcons.person),
            largeTitle: Text('Navigation bar title'),
            trailing: Icon(CupertinoIcons.plus),
          )
        ],
      ),
    );
  }
}

実行結果

メモ

下記の記事が興味深い

https://qiita.com/sunagakuuun/items/1c6fb0dd0e50d8e8deb6

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoSwitch

https://api.flutter.dev/flutter/cupertino/CupertinoSwitch-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool _value = true;

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoSwitch(
          value: _value,
          onChanged: (value) {
            setState(() {
              _value = value;
            });
          },
        ),
      ),
    );
  }
}

実行結果

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoTabScaffold + Bar + View

https://api.flutter.dev/flutter/cupertino/CupertinoTabScaffold-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  
  Widget build(BuildContext context) {
    return CupertinoTabScaffold(
      tabBar: CupertinoTabBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(CupertinoIcons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(CupertinoIcons.search_circle_fill),
            label: 'Explore',
          ),
        ],
      ),
      tabBuilder: (context, index) {
        return CupertinoTabView(
          builder: (context) {
            return CupertinoPageScaffold(
              navigationBar: CupertinoNavigationBar(
                middle: Text('Page 1 of tab $index'),
              ),
              child: Center(
                child: CupertinoButton(
                  onPressed: () {
                    Navigator.of(context).push(
                      CupertinoPageRoute<void>(
                        builder: (context) {
                          return CupertinoPageScaffold(
                              navigationBar: CupertinoNavigationBar(
                                middle: Text('Page 2 of tab $index'),
                              ),
                              child: Center(
                                child: CupertinoButton(
                                  onPressed: () {
                                    Navigator.of(context).pop();
                                  },
                                  child: const Text('Back'),
                                ),
                              ));
                        },
                      ),
                    );
                  },
                  child: const Text('Next page'),
                ),
              ),
            );
          },
        );
      },
    );
  }
}

実行結果

メモ

タブを変更した時に元のタブのページがちゃんと保存されているのがすごい

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoTextField

https://api.flutter.dev/flutter/cupertino/CupertinoTextField-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late TextEditingController _textEditingController;

  
  void initState() {
    super.initState();
    _textEditingController = TextEditingController(text: "initial text");
  }

  
  void dispose() {
    _textEditingController.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoTextField(
          controller: _textEditingController,
        ),
      ),
    );
  }
}

実行結果

メモ

inital text を設定するのがとても大変

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

CupertinoTimerPicker

https://api.flutter.dev/flutter/cupertino/CupertinoTimerPicker-class.html

コード

main.dart
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('Navigation bar title'),
      ),
      child: Center(
        child: CupertinoButton(
          onPressed: () {
            showCupertinoModalPopup(
              context: context,
              builder: (context) {
                return Container(
                  color: CupertinoColors.systemBackground.resolveFrom(context),
                  height: 216,
                  child: CupertinoTimerPicker(
                    onTimerDurationChanged: (value) {},
                  ),
                );
              },
            );
          },
          child: const Text('Show time picker'),
        ),
      ),
    );
  }
}

実行結果

このスクラップは2023/01/10にクローズされました