diff --git a/image/provider_example.gif b/image/provider_example.gif new file mode 100644 index 0000000..dfb6f15 Binary files /dev/null and b/image/provider_example.gif differ diff --git a/mecury_project/example/provider_example/README.md b/mecury_project/example/provider_example/README.md index 228f3e5..06a8345 100644 --- a/mecury_project/example/provider_example/README.md +++ b/mecury_project/example/provider_example/README.md @@ -3,8 +3,12 @@ ## 简介 使用 Google 官方推荐的状态管理 [Provider](https://pub.dev/packages/provider#-installing-tab-) 的 demo。详细了解请看这里:[Flutter | 状态管理指南篇——Provider](https://juejin.im/editor/posts/5d00a84fe51d455a2f22023f) + + +[更新]:Demo 新增单页面状态提供方式,供参考 + ## 样例 -![](https://user-gold-cdn.xitu.io/2019/6/12/16b4c691828e5a7a?w=333&h=676&f=gif&s=235209) +![provider_example](../../../image/provider_example.gif) ## Getting Started diff --git a/mecury_project/example/provider_example/lib/color_model.dart b/mecury_project/example/provider_example/lib/color_model.dart new file mode 100644 index 0000000..c9b35b3 --- /dev/null +++ b/mecury_project/example/provider_example/lib/color_model.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; + +class ColorModel with ChangeNotifier { + int _seed = 0xFFFF9000; + Color _color = Color(0xFFFF9000); + + get color => _color; + + changeColor() { + _seed += 30; + _color = Color(_seed); + notifyListeners(); + } +} diff --git a/mecury_project/example/provider_example/lib/generated/i18n.dart b/mecury_project/example/provider_example/lib/generated/i18n.dart deleted file mode 100644 index 2dcf836..0000000 --- a/mecury_project/example/provider_example/lib/generated/i18n.dart +++ /dev/null @@ -1,122 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -// ignore_for_file: non_constant_identifier_names -// ignore_for_file: camel_case_types -// ignore_for_file: prefer_single_quotes - -// This file is automatically generated. DO NOT EDIT, all your changes would be lost. -class S implements WidgetsLocalizations { - const S(); - - static const GeneratedLocalizationsDelegate delegate = - GeneratedLocalizationsDelegate(); - - static S of(BuildContext context) => Localizations.of(context, S); - - @override - TextDirection get textDirection => TextDirection.ltr; - -} - -class $en extends S { - const $en(); -} - -class GeneratedLocalizationsDelegate extends LocalizationsDelegate { - const GeneratedLocalizationsDelegate(); - - List get supportedLocales { - return const [ - Locale("en", ""), - ]; - } - - LocaleListResolutionCallback listResolution({Locale fallback, bool withCountry = true}) { - return (List locales, Iterable supported) { - if (locales == null || locales.isEmpty) { - return fallback ?? supported.first; - } else { - return _resolve(locales.first, fallback, supported, withCountry); - } - }; - } - - LocaleResolutionCallback resolution({Locale fallback, bool withCountry = true}) { - return (Locale locale, Iterable supported) { - return _resolve(locale, fallback, supported, withCountry); - }; - } - - @override - Future load(Locale locale) { - final String lang = getLang(locale); - if (lang != null) { - switch (lang) { - case "en": - return SynchronousFuture(const $en()); - default: - // NO-OP. - } - } - return SynchronousFuture(const S()); - } - - @override - bool isSupported(Locale locale) => _isSupported(locale, true); - - @override - bool shouldReload(GeneratedLocalizationsDelegate old) => false; - - /// - /// Internal method to resolve a locale from a list of locales. - /// - Locale _resolve(Locale locale, Locale fallback, Iterable supported, bool withCountry) { - if (locale == null || !_isSupported(locale, withCountry)) { - return fallback ?? supported.first; - } - - final Locale languageLocale = Locale(locale.languageCode, ""); - if (supported.contains(locale)) { - return locale; - } else if (supported.contains(languageLocale)) { - return languageLocale; - } else { - final Locale fallbackLocale = fallback ?? supported.first; - return fallbackLocale; - } - } - - /// - /// Returns true if the specified locale is supported, false otherwise. - /// - bool _isSupported(Locale locale, bool withCountry) { - if (locale != null) { - for (Locale supportedLocale in supportedLocales) { - // Language must always match both locales. - if (supportedLocale.languageCode != locale.languageCode) { - continue; - } - - // If country code matches, return this locale. - if (supportedLocale.countryCode == locale.countryCode) { - return true; - } - - // If no country requirement is requested, check if this locale has no country. - if (true != withCountry && (supportedLocale.countryCode == null || supportedLocale.countryCode.isEmpty)) { - return true; - } - } - } - return false; - } -} - -String getLang(Locale l) => l == null - ? null - : l.countryCode != null && l.countryCode.isEmpty - ? l.languageCode - : l.toString(); diff --git a/mecury_project/example/provider_example/lib/screens.dart b/mecury_project/example/provider_example/lib/screens.dart index 4a8c7d1..8199c43 100644 --- a/mecury_project/example/provider_example/lib/screens.dart +++ b/mecury_project/example/provider_example/lib/screens.dart @@ -1,11 +1,14 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'counter_model.dart'; +import 'color_model.dart'; class FirstScreen extends StatelessWidget { @override Widget build(BuildContext context) { - final counter = Provider.of(context,); + final counter = Provider.of( + context, + ); final textSize = Provider.of(context); return Scaffold( @@ -29,32 +32,116 @@ class FirstScreen extends StatelessWidget { } } +/// This is a single page provider, +/// it will be destroyed when the page is removed, +/// and the status will be reset. + +class SecondScreenProvider extends StatefulWidget { + final Widget child; + + SecondScreenProvider({@required this.child}); + + @override + _SecondScreenProviderState createState() => _SecondScreenProviderState(); +} + +class _SecondScreenProviderState extends State { + ColorModel _colorModel = ColorModel(); + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider.value( + value: _colorModel, + child: widget.child, + ); + } +} + class SecondScreen extends StatelessWidget { @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('Second Page'), + return SecondScreenProvider( + child: DefaultTabController( + length: 3, + child: Scaffold( + appBar: buildAppBar(), + body: TabBarView(children: [ + buildCounterText(), + showIconWithColor(), + showIconWithColor(), + ]), + floatingActionButton: buildActionButtons(), + ), ), - body: Consumer2( - builder: (context, CounterModel counter, int textSize, child) { - return Center( - child: Text( - 'Value: ${counter.value}', - style: TextStyle( - fontSize: textSize.toDouble(), - ), + ); + } + + Column buildActionButtons() { + return Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Consumer( + builder: (context, ColorModel colorModel, child) { + return FloatingActionButton( + heroTag: 'no_hero', + child: Icon(Icons.swap_horizontal_circle), + onPressed: () { + colorModel.changeColor(); + }, + ); + }, + ), + SizedBox(height: 20), + Consumer( + builder: (context, CounterModel counter, child) => + FloatingActionButton( + onPressed: () => counter.increment(), + child: child, + ), + child: Icon(Icons.add), + ), + ], + ); + } + + Consumer2 buildCounterText() { + return Consumer2( + builder: (context, CounterModel counter, int textSize, child) { + return Center( + child: Text( + 'Value: ${counter.value}', + style: TextStyle( + fontSize: textSize.toDouble(), ), + ), + ); + }, + ); + } + + AppBar buildAppBar() { + return AppBar( + title: Text('Second Page'), + bottom: TabBar(tabs: [ + Tab(text: 'show counter'), + Tab(text: 'show color'), + Tab(text: 'show color'), + ]), + ); + } + + Container showIconWithColor() { + return Container( + alignment: Alignment.center, + child: Consumer( + builder: (context, ColorModel colorModel, child) { + return Icon( + Icons.stars, + color: colorModel.color, + size: 100, ); }, ), - floatingActionButton: Consumer( - builder: (context, CounterModel counter, child) => FloatingActionButton( - onPressed: () => counter.increment(), - child: child, - ), - child: Icon(Icons.add), - ), ); } }