flutter的局部刷新的几种方式
第一种 :使用 GlobalKey
父组件中声明
GlobalKey<_局部刷新对象类型State> textKey = GlobalKey();
textKey.currentState.局部刷新的方法();
第二种
使用:StatefulBuilder
第三种
使用 StreamBuilder + StreamController FutureBuilder & StreamBuilder
第三种:provider (也是异步通信)
ChangeNotifier + ChangeNotifierProvider
第四种 (也是异步通信) :Flutter ValueNotifier 异步通信、ValueListenableBuilder - 知乎
ValueNotifier + ValueListenableBuilder
第一种:使用 GlobalKey
globalkey唯一定义了某个element,它使你能够访问与element相关联的其他对象,例如buildContext、state等。
使用场景:可以通过key.currentState拿到它的状态对象,然后就可以调用其中的onPressed方法。
//请求刷新 setState((){ }); #State @override Widget build(BuildContext context) { //构建新的Widget return new Text(_text); }
那么,如果 我们能将 build方法中的 return new Text(_text) 暴漏出去,我们就可以实现通用的 局部刷新 Widget。
实现方案
- 接口回调,将return new Text(_text);暴露出去:
用typedef function实现
//定义函数别名 typedef BuildWidget = Widget Function();
将函数别名 BuildWidget 作为参数,传递到State.build方法即可
完整代码
import 'package:flutter/material.dart'; //封装 通用局部刷新工具类//定义函数别名typedef BuildWidget = Widget Function(); class PartRefreshWidget extends StatefulWidget { PartRefreshWidget(Key key, this._child): super(key: key); BuildWidget _child; @override State createState() { return PartRefreshWidgetState(_child); } } class PartRefreshWidgetState extends State { BuildWidget child; PartRefreshWidgetState(this.child); @override Widget build(BuildContext context) { return child.call(); } void update() { print('update'); setState(() { }); } }
使用:
import 'package:flutter/material.dart'; import 'PartRefreshWidget.dart'; class GlobalKeyDemo extends StatefulWidget { @override _GlobalKeyDemoState createState() => _GlobalKeyDemoState();} class _GlobalKeyDemoState extends State { int _count = 0; //使用1 创建GlobalKey GlobalKey globalKey = new GlobalKey(); @override Widget build(BuildContext context) { print('----------------build'); return Scaffold( appBar: AppBar( title: Text("inheritedWidget"), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ //使用2 创建通用局部刷新widget PartRefreshWidget(globalKey, () { ///创建需要局部刷新的widget return Text( '变化的:$_count', style: TextStyle(color: Colors.green), ); }), Text('不变的: $_count'), RaisedButton( onPressed: () { //点击 _count++; //使用3调用刷新方法 globalKey.currentState.update(); }, ), ], ), ) ); }}
转载:https://blog.csdn.net/jdsjlzx/article/details/123560075
第二种:使用:StatefulBuilder
使用情景:
多选和单选
单选的时候,选中一个就可以直接把结果返回,因此本身底部弹窗无需状态管理。但到多选的时候,需要知道当前选中的选项,有选项被点击的时候需要存储下来,当再次被点击的时候要清空这个选项,同时界面还需要同步更新,因此就涉及到状态管理了。
实现方式 内部使用。
在Flutter 中提供了一个 StatefulBuilder
的类,提供了一个 builder
方法构建有状态组件,并且提供了状态更新方法,因此在里面完成状态管理。
在这个 builder
方法中,setState
其实就是对应状态组件的setState
对应的方法,这个 state 就是用于控制 StatefulBuilder
生成的组件的状态的。这种方式有点类似于 React
的 useState
的钩子函数用法
使用的核心代码:
class DemoStatefulBuilderPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( //状态构建器 body: buildStatefulBuilder(), ); }}
int _count = 0; StatefulBuilder buildStatefulBuilder() { return StatefulBuilder( //构建状态改变的Widget builder: (BuildContext context, void Function(void Function()) setState) { //居中 return Center( //手势识别 child: GestureDetector( child: Text("早起的年轻人 $_count"), //单击事件 onTap: () { //刷新当前 StatefulBuilder 中的状态 setState(() { _count++; }); }, ), ); }, ); }
第三种 使用 FutureBuilder & StreamBuilder
使用场景:异步UI更新
很多时候我们会依赖一些异步数据来动态更新UI,比如在打开一个页面时我们需要先从互联网上获取数据,在获取数据的过程中显示一个加载框,等获取到数据时我们再渲染页面;又比如我们想展示Stream(比如文件流、互联网数据接收流)的进度。当然StatefulWidget我们完全可以实现以上功能。但由于在实际开发中依赖异步数据更新UI的这种场景非常常见,并且当StatefulWidget中控件树较大时,更新一个属性导致整个树重建,消耗性能,因此Flutter专门提供了FutureBuilder和SteamBuilder两个组件来快速实现这种功能。
FutureBuilder的使用
const FutureBuilder({ Key key, this.future, //获取数据的方法 获取用户异步处理获得数据的代码 this.initialData, //初始的默认数据 初始化数据加载 @required this.builder //数据快照 回调函数,暴露异步处理中的快照。这个是我们构建组件的主要组成。 主要来看一下它的构造函数: }) : assert(builder != null), super(key: key);
class _MyHomePageState extends State { Future mockNetworkData() async { return Future.delayed(Duration(seconds: 2), () => "我是从互联网上获取的数据"); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'You have pushed the button this many times:', ), FutureBuilder( future: mockNetworkData(), builder: (BuildContext context, AsyncSnapshot snapshot){ if(snapshot.connectionState == ConnectionState.done){ if(snapshot.hasError){ // 请求失败,显示错误 return Text("Error: ${snapshot.error}"); }else { // 请求成功,显示数据 return Text("Contents: ${snapshot.data}"); } }else { return CircularProgressIndicator(); } }), ], ), ), // This trailing comma makes auto-formatting nicer for build methods. ); }}
SteamBuilder的使用
class _MyHomePageState extends State { Stream counter(){ return Stream.periodic(Duration(seconds: 1), (i){ return i; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'You have pushed the button this many times:', ), StreamBuilder( stream: counter(), builder: (BuildContext context, AsyncSnapshot snapshot){ if(snapshot.hasError){ return Text("Error: ${snapshot.error}"); } switch (snapshot.connectionState){ case ConnectionState.none: return Text("没有Stream"); case ConnectionState.waiting: return Text("等待数据、、、"); case ConnectionState.active: return Text("active: ${snapshot.data}"); case ConnectionState.done: return Text("Stream已关闭"); } return null; }), ], ), ), // This trailing comma makes auto-formatting nicer for build methods. ); }}
StreamBuilder与StreamController的详细使用:https://blog.csdn.net/u010194271/article/details/128024208
来源地址:https://blog.csdn.net/qq_27909209/article/details/130523131