DartでProviderを使って値の変更を監視して更新する
公開日: 2024-06-05 22:14:41
Dartで別ファイルでの値の変更を検知して、Viewに変更を反映させるコードを使うことがあったので、復習がてら履歴として残そうと思います。
こちらは、SwiftUIのObservedObjectという概念によく似ています。
main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'user_view_model.dart';
import 'home_screen.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => UserViewModel()), // UserViewModelをプロバイダーとして設定
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(), // ホーム画面を表示
);
}
}main.dartではProviderの[ ]の中にViewModelをラップしています。
親Viewにこちらを記載する必要があります。
ViewModel
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class UserViewModel with ChangeNotifier {
int _userLevel = 0;
int get userLevel => _userLevel;
UserViewModel() {
_loadUserLevel();
}
Future<void> _loadUserLevel() async {
final prefs = await SharedPreferences.getInstance();
_userLevel = prefs.getInt('userLevel') ?? 0;
notifyListeners(); // 値の変更を通知
}
void setUserLevel(int level) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('userLevel', level);
_userLevel = level;
notifyListeners(); // 値の変更を通知
}
}ViewModelで値の変更を行った後には
notifyListeners(); // 値の変更を通知
この部分を呼び出すことで使用する画面に反映される仕組みです。
HomeScreen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:badges/badges.dart' as badges;
import 'user_view_model.dart';
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _currentIndex = 0;
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
if (index == 0 || index == 2) {
var userViewModel = Provider.of<UserViewModel>(context, listen: false);
userViewModel.setUserLevel(userViewModel.userLevel - 1); // 一例として
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: Consumer<UserViewModel>( // UserViewModelを監視し、UIを更新
builder: (context, userViewModel, child) {
return BottomNavigationBar(
onTap: onTabTapped,
currentIndex: _currentIndex,
items: [
BottomNavigationBarItem(
icon: badges.Badge(
showBadge: userViewModel.userLevel > 0, // ユーザーレベルに基づいてバッジを表示
badgeContent: Text(userViewModel.userLevel.toString(), style: TextStyle(color: Colors.white)),
child: Icon(Icons.dashboard),
),
label: 'Bulletin Board',
),
BottomNavigationBarItem(
icon: badges.Badge(
showBadge: userViewModel.userLevel == 1, // ユーザーレベルに基づいてバッジを表示
badgeContent: Text('1', style: TextStyle(color: Colors.white)),
child: Icon(Icons.post_add),
),
label: 'Post',
),
BottomNavigationBarItem(
icon: badges.Badge(
showBadge: userViewModel.userLevel > 1, // ユーザーレベルに基づいてバッジを表示
badgeContent: Text(userViewModel.userLevel.toString(), style: TextStyle(color: Colors.white)),
child: Icon(Icons.settings),
),
label: 'Settings',
),
],
);
},
),
);
}
}
HomeScreen.dart (View側)では
bottomNavigationBar: Consumer<UserViewModel>( ) //UserViewModelの
こちらでラップしてある箇所にのみ変更された値が届くようです。
他の部分でもUserViewModelの変更を監視して反映したい場合は、同様にConsumer<UserViewModel>でラップするか、Provider.of<UserViewModel>(context)を使用して直接モデルにアクセスすることができます。ただし、直接アクセスする場合は再描画が自動的に行われないため、手動でsetState()を呼び出す必要があります。
実行結果

今回はViewModelの値を監視、ユーザーレベルの値に応じて、HomeScreenで変更を検知して、バッチを表示させるサンプルコードでした。