flutter 跨模組之間資料共享實踐
阿新 • • 發佈:2021-02-11
技術標籤:Flutter知識梳理
001 Provider
它是inheritedWidget語法糖。提供了依賴註冊的功能,允許Widget樹中更加靈活處理和傳遞資料
依賴註冊是一種可以讓我們在需要的時提取到所需資源的機制,換句話說是預先將某種資源放到程式中的某個我們都可以訪問的
的位置,當需要使用這個資源時,直接去這個位置拿即可,無需關心資源時誰放進去。
封裝的資料來源不僅需要為子widget提供讀的能力,還要提供寫的能力,需要使用ChangeNotifierProvider.value。
獲取Provider的資料
final _counter = Provider.of<CounterModel>(context);
final textSize = Provider.of<double>(context);
002 Consumer
就是比Provider更加方便,一次性獲取到兩個引數,就很方便快捷,效率高,除此之外還可以控制UI重新整理的粒度,避免與資料無關元件的無用重新整理。
003 程式碼
main.dart
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'counter_model.dart'; import 'provider_demo.dart'; import 'consumer_demo.dart'; void main() { runApp(MyApp1()); } class MyApp1 extends StatelessWidget { const MyApp1({Key key}) : super(key: key); @override Widget build(BuildContext context) { return MultiProvider( providers: [ Provider.value(value: 30.0), ChangeNotifierProvider.value(value: CounterModel()) ], child: MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: HomePage()), ); } } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( // This is the theme of your application. // // Try running your application with "flutter run". You'll see the // application has a blue toolbar. Then, without quitting the app, try // changing the primarySwatch below to Colors.green and then invoke // "hot reload" (press "r" in the console where you ran "flutter run", // or simply save your changes to "hot reload" in a Flutter IDE). // Notice that the counter didn't reset back to zero; the application // is not restarted. primarySwatch: Colors.blue, // This makes the visual density adapt to the platform that you run // the app on. For desktop platforms, the controls will be smaller and // closer together (more dense) than on mobile platforms. visualDensity: VisualDensity.adaptivePlatformDensity, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } class HomePage extends StatelessWidget { const HomePage({Key key}) : super(key: key); @override Widget build(BuildContext context) { return DefaultTabController( length: 2, child: Scaffold( body: TabBarView( children: [ConsumerTabPage1(), ProviderTabPage1()], ), bottomNavigationBar: TabBar( tabs: [ Tab( icon: Icon(Icons.home), text: "Cos", ), Tab( icon: Icon(Icons.hot_tub), text: "Pro", ) ], unselectedLabelColor: Colors.blueGrey, labelColor: Colors.blue, indicatorSize: TabBarIndicatorSize.label, indicatorColor: Colors.greenAccent, ), ), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect // how it looks. // This class is the configuration for the state. It holds the values (in this // case the title) provided by the parent (in this case the App widget) and // used by the build method of the State. Fields in a Widget subclass are // always marked "final". final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { // This call to setState tells the Flutter framework that something has // changed in this State, which causes it to rerun the build method below // so that the display can reflect the updated values. If we changed // _counter without calling setState(), then the build method would not be // called again, and so nothing would appear to happen. _counter++; }); } @override Widget build(BuildContext context) { // This method is rerun every time setState is called, for instance as done // by the _incrementCounter method above. // // The Flutter framework has been optimized to make rerunning build methods // fast, so that you can just rebuild anything that needs updating rather // than having to individually change instances of widgets. return Scaffold( appBar: AppBar( // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. title: Text(widget.title), ), body: Center( // Center is a layout widget. It takes a single child and positions it // in the middle of the parent. child: Column( // Column is also a layout widget. It takes a list of children and // arranges them vertically. By default, it sizes itself to fit its // children horizontally, and tries to be as tall as its parent. // // Invoke "debug painting" (press "p" in the console, choose the // "Toggle Debug Paint" action from the Flutter Inspector in Android // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) // to see the wireframe for each widget. // // Column has various properties to control how it sizes itself and // how it positions its children. Here we use mainAxisAlignment to // center the children vertically; the main axis here is the vertical // axis because Columns are vertical (the cross axis would be // horizontal). mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); } }
comsumer_demo.dart
import 'package:flutter/material.dart'; import 'counter_model.dart'; import 'package:provider/provider.dart'; import 'test_icon.dart'; class ConsumerTabPage1 extends StatelessWidget { @override Widget build(BuildContext context) { final _counter = Provider.of<CounterModel>(context); final textSize = Provider.of<double>(context); return Scaffold( appBar: AppBar( title: Text('First Page'), ), body: Center( child: Text( 'Counter: ${_counter.counter}', style: TextStyle(fontSize: textSize), ), ), floatingActionButton: FloatingActionButton( onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => ConsumerTabPage2())), child: Icon(Icons.navigate_next), ), ); } } class ConsumerTabPage2 extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Second Page'), ), body: Consumer2<CounterModel,double>( builder: (context, CounterModel counter, double textSize, _) => Text( 'Counter: ${counter.counter}', style: TextStyle(fontSize: textSize)) ), floatingActionButton: Consumer<CounterModel>( builder: (context, CounterModel counter, child) => FloatingActionButton( onPressed: counter.increment, child: child, ), child: TestIcon(), ), ); } }
counter_model.dart
import 'package:flutter/foundation.dart';
class CounterModel with ChangeNotifier {
int _count = 0;
int get counter => _count;
void increment() {
_count++;
notifyListeners();
}
}
provider_demo.dart
import 'package:flutter/material.dart';
import 'counter_model.dart';
import 'package:provider/provider.dart';
import 'test_icon.dart';
class ProviderTabPage1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
final _counter = Provider.of<CounterModel>(context);
final textSize = Provider.of<double>(context);
return Scaffold(
appBar: AppBar(
title: Text('First Page'),
),
body: Center(
child: Text(
'Counter: ${_counter.counter}',
style: TextStyle(fontSize: textSize),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => ProviderTabPage2())),
child: Icon(Icons.navigate_next),
),
);
}
}
class ProviderTabPage2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
final _counter = Provider.of<CounterModel>(context);
final textSize = Provider.of<double>(context);
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Text(
'Counter: ${_counter.counter}',
style: TextStyle(fontSize: textSize),
),
floatingActionButton: FloatingActionButton(
onPressed: _counter.increment,
child: TestIcon(),
),
);
}
}
test_icon.dart
import 'package:flutter/material.dart';
class TestIcon extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("TestIcon build");
return Icon(Icons.add);
}
}
參考資料