这里说的Flutter中Widget之间的联动方式是指一个Widget更新后,另一个Widget得到响应并更新,我们称之为Flutter中Widget之间的联动。下面介绍几种Widget联动的方式。
第一种方式:重新刷新页面
通过setState刷新整个页面,达到更新数据的方式更新对应的控件,代码如下:
/*
* @Author: yz.yujingzhou
* @Date: 2020-09-11 22:14:38
* @Last Modified by: yz.yujingzhou
* @Last Modified time: 2020-09-11 22:42:54
**/
import 'package:flutter/material.dart';
class Way1 extends StatefulWidget {
@override
_Way1State createState() => _Way1State();
}
class _Way1State extends State<Way1> {
int count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
alignment: Alignment.center,
child: Column(
children: <Widget>[
GestureDetector(
onTap: (){
count--;
setState(() {
});
},
child: Text('Widget1 Click count-- $count'),
),
Text('I don\'t want to change -- $count'),
GestureDetector(
onTap: (){
count++;
setState(() {
});
},
child: Text('Widget2 Click count++ $count'),
)
],
),
),
);
}
}
优点:写法简单明了;
缺点:其实是Widget之间的联动,却需要需要刷新整个页面;
第二种方式:StatefulBuilder / StatefulWidget
这是一种方式的两种实现,StatefulBuilder方式支持在同一个类内直接嵌入Widget实现,而StatefulWidget方式需要把控件另外封装成单独类的方式实现;
适合控件间点对点的控制场景;
先来看看StatefulBuilder的实现方式,代码如下:
/*
* @Author: yz.yujingzhou
* @Date: 2020-09-11 22:14:38
* @Last Modified by: yz.yujingzhou
* @Last Modified time: 2020-09-11 22:47:12
**/
import 'package:flutter/material.dart';
class Way2 extends StatefulWidget {
@override
_Way2State createState() => _Way2State();
}
class _Way2State extends State<Way2> {
int count = 0;
StateSetter stateSetter1;
StateSetter stateSetter2;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
alignment: Alignment.center,
child: Column(
children: <Widget>[
StatefulBuilder(
builder: (BuildContext context, StateSetter stateSetter){
stateSetter1 = stateSetter;
return GestureDetector(
onTap: (){
count++;
stateSetter2(() {
});
},
child: Text('Widget1 Click count++ $count'),
);
}
),
Text('I don\'t want to change -- $count'),
StatefulBuilder(
builder: (BuildContext context, StateSetter stateSetter){
stateSetter2 = stateSetter;
return GestureDetector(
onTap: (){
count++;
stateSetter1(() {
});
},
child: Text('Widget2 Click count++ $count'),
);
}
),
],
),
),
);
}
}
StatefulWidget的实现方式需要封装成两个类,再把各个类的StateSetter通过回调或GlobalKey的方式提供给其它Widget调用达到相互调用的目的,代码很简单就不列举了。
优点:实现联动并点对点局部刷新,适合同一页面位置相互比较接近的Widget之间联动;
第三种方式:ChangeNotifier
这种方式官方控件用得比较多,如TabView,是我比较喜欢用的一种小范围内通知方式,和StatefulWidget类似需要封装,但不需要依赖GlobalKey和回调,很适合页面控件控制某块内容的场景即页对点的控制,同时允许传递值,使用方式如下:
/*
* @Author: yz.yujingzhou
* @Date: 2020-09-11 22:14:38
* @Last Modified by: yz.yujingzhou
* @Last Modified time: 2020-09-11 23:11:50
**/
import 'package:flutter/material.dart';
class Way3 extends StatefulWidget {
@override
_Way3State createState() => _Way3State();
}
class _Way3State extends State<Way3> {
Way3Controller controller;
@override
void initState() {
super.initState();
controller = Way3Controller(value: 0);
}
@override
void dispose() {
super.dispose();
controller?.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
alignment: Alignment.center,
child: Column(
children: <Widget>[
GestureDetector(
onTap: (){
controller.value++;
controller.trigger();
},
child: Text('Widget1 Click'),
),
Text('I don\'t want to change'),
Widget2(controller: controller)
],
),
),
);
}
}
class Widget2 extends StatefulWidget {
final Way3Controller controller;
Widget2({this.controller});
@override
_Widget2State createState() => _Widget2State();
}
class _Widget2State extends State<Widget2> {
@override
void initState() {
super.initState();
widget.controller?.addListener((){
setState(() {
});
});
}
@override
Widget build(BuildContext context) {
return Text('Widget2 Click count++ ${widget.controller?.value}');
}
}
class Way3Controller extends ChangeNotifier {
int value;
Way3Controller({this.value});
trigger() {
notifyListeners();
}
}
第四种方式:InheritedWidget / Provider / Redux
适合较有树形层级的联动场景及信息通信;
第五种方式:EventBus
适合较离散的控件之间的联动场景及信息通信;
Demo代码: