Flutter 局部刷新

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<T extends StatefulWidget>
  @override
  Widget build(BuildContext context) {
    //构建新的Widget
    return new Text(_text);
  }
 

那么,如果 我们能将 build方法中的 return new Text(_text) 暴漏出去,我们就可以实现通用的 局部刷新 Widget。

实现方案

  1. 接口回调,将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<StatefulWidget> createState() {
    return PartRefreshWidgetState(_child);
  }
 
}
 
class PartRefreshWidgetState extends State<PartRefreshWidget> {
 
  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<GlobalKeyDemo> {
  int _count = 0;
 
  //使用1 创建GlobalKey
  GlobalKey<PartRefreshWidgetState> 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: <Widget>[
              //使用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<MyHomePage> {

  Future<String> 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: <Widget>[
            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<MyHomePage> {

  Stream<int> 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: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            StreamBuilder(
                stream: counter(),
                builder: (BuildContext context, AsyncSnapshot<int> 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

猜你喜欢

转载自blog.csdn.net/qq_27909209/article/details/130523131