はじめに
実現したい事としては、DropdownButton
で値を選択した時に
①選択した値に表示を変える
②選択した値をriverpodで保持する
よくStatefulWidget
を使ってDropdownButton
を実装するサンプルは探せばたくさん出てきますが、riverpodを使って同じことをできないかやってみました。
イメージはこんな感じ
riverpodでDropdownButton選択時に値を保持して表示を変える pic.twitter.com/PFXTFjmfmf
— Gento アプリ&web (@gento34165638) January 15, 2023
環境と前提
$ flutter --version (git)-[master]
Flutter 3.3.9 • channel stable • https://github.com/flutter/flutter.git
Framework • revision b8f7f1f986 (7 weeks ago) • 2022-11-23 06:43:51 +0900
Engine • revision 8f2221fbef
Tools • Dart 2.18.5 • DevTools 2.15.0
使うパッケージはflutter_riverpod
です。
hooksと併用のhooks_riverpod
ではありません。
pubspec.yaml
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
flutter_riverpod: ^2.1.1
ProviderScopeでMyApp
を囲む部分は省いています!
コード全文
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
// DropdownMenuItemの初期値を設定
final numberProvider = StateProvider<int?>((ref) {
return 5;
});
class NumberMembersScreen extends ConsumerStatefulWidget {
const NumberMembersScreen({super.key});
@override
ConsumerState<ConsumerStatefulWidget> createState() => _NumberMembersScreen();
}
class _NumberMembersScreen extends ConsumerState<NumberMembersScreen> {
// DropdownButtonで表示される選択肢
List<int> items = [3, 4, 5];
// DropdownButtonで選択した値
int? _selectedItem;
@override
Widget build(BuildContext context) {
var _screenSize = MediaQuery.of(context).size;
// 選択した値をwatchで監視する
final numberOfMember = ref.watch(numberProvider);
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'人数を入力してな',
),
// 監視しているnumberOfMemberが変更されるたびに再描画される
Text(
numberOfMember.toString(),
),
const SizedBox(height: 15),
SizedBox(
width: _screenSize.width * 0.4,
child: DropdownButton(
hint: const Text('人数を選んで'),
isExpanded: true,
value: _selectedItem,
items: items
.map((item) => DropdownMenuItem<int>(
alignment: AlignmentDirectional.center,
value: item,
child: Text(item.toString()),
))
.toList(),
onChanged: (int? value) {
// riverpodで保持している値を選択した値に更新する
ref.read(numberProvider.notifier).state = value;
// 画面に表示させるDropdownButtonの値を動的に変える
setState(() {
_selectedItem = value;
});
print(ref.read(numberProvider.notifier).state);
},
)),
],
),
),
);
}
}
ちなみに、もしDropdownButton
のhint
を消すと、初期値は何も表示されなくなる
これでDropdownButton
選択時にriverpodを使って値をグローバルに保持することができました!!