Flutter 数据传递

在应用开发过程中数据传递,flutter提供 InheritedWidget 以及多种 provider, 各有差异从从使用习惯上面 这边主要介绍以下两种:

  • InheritedWidget
  • provider   (ChangeNotifier)

 InheritedWidget:

提供一种 从上而下 的数据提供 (而且子节点需要  Widget 包裹); 且单向切记只能由上而下的刷新数据;不能做到 子节点  变数据 而刷新的情况!常用于 静态数据的存储;不会改变的常量保存; 或者子节点只作为 静态展示的数据父节点提供元数据。子节点展示数据 不参与动态更新交互

 

效果如下:

脚本结构:

 inherited_datum.dart

import 'package:flutter/cupertino.dart';

class InheritedDatum extends InheritedWidget {
  final int count;
  const InheritedDatum({Key? key, required child, required this.count})
      : super(key: key, child: child);

  static InheritedDatum? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<InheritedDatum>();
  }

  ///**子组件不能 通过调用该方法 实现子组件刷新
  updateCount(int count) {
    count = count;
  }

  @override
  bool updateShouldNotify(covariant InheritedDatum oldWidget) {
    // TODO: implement updateShouldNotify
    return oldWidget.count != count;
  }
}

widget_child0.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import 'inherited_datum.dart';

class WidgetChild0 extends StatelessWidget {
  const WidgetChild0({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.blue,
      height: 40,
      width: 80,
      child: Center(
        child: Text(
          '${InheritedDatum.of(context)?.count}',
          style: TextStyle(color: Colors.white),
        ),
      ),
    );
  }
}

widget_child1.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import 'inherited_datum.dart';

class WidgetChild1 extends StatelessWidget {
  const WidgetChild1({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.blue,
      height: 40,
      width: 80,
      child: Center(
        child: Text(
          '${InheritedDatum.of(context)?.count}',
          style: TextStyle(color: Colors.white),
        ),
      ),
    );
  }
}

入口:main.dart

@override
Widget build(BuildContext context) {
  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(
      child: InheritedDatum(
        count: _counter,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          // children: const [],
          children: const [WidgetChild0(), WidgetChild1()],
        ),
      ),
    ),
    floatingActionButton: FloatingActionButton(
      onPressed: _incrementCounter,
      tooltip: 'Increment',
      child: const Icon(Icons.add),
    ), // This trailing comma makes auto-formatting nicer for build methods.
  );
}

InheritedWidget   使用注意细节:

1. 必须是 子组件平行的都不行:

2. 子组件获取 InheritedWidget 中的数据 通过

InheritedDatum.of(context)?.count

3. 子组件不能仅 通过调用 InheritedWidget 中的方便实现 子组件刷新

小结

        InheritedWidget 的适用场景:子组件共享 父组件中的数据;但不具备 修改更新 父组件中数据的 能力!下面介绍的 ChangeNotifier 则具备 上下 更新数据的能力

provider    数据传递

provider是基于InheritedWidget 的包装 ;为了在Provider中进行数据共享首先我们需要为其定义一个数据模型,为了能够订阅数据的状态通常会让这个数据模型来继承 ChangeNotifier,达到更新的目的; 使用前先导入provider: ^6.0.5

dependencies:
  flutter:
    sdk: flutter

  provider: ^6.0.5

之前的总结https://johns.blog.csdn.net/article/details/122139508

需要在父节点中使用以下 组件来完成 子组件的更新:按照自己 更新逻辑的 复杂度。按照实际需要选取适合的 模型

  • ChangeNotifierProvider
  • ProxyProvider
  • MultiProvider
  • Consumer

效果如下:

父组件 和 子组件都可以 实现对数据的更新

 

脚本结构:

counter.dart

import 'package:flutter/cupertino.dart';

class Counter with ChangeNotifier {
  int _count = 0;
  int get count => _count;
  void increment() {
    _count++;
    notifyListeners();
  }

  void set(int count) {
    _count = count;
    notifyListeners();
  }
}

 widget_child0.dart

import 'package:untitled1/counter.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class WidgetChild0 extends StatelessWidget {
  const WidgetChild0({Key? key}) : super(key: key);

  Widget build(BuildContext context) {
    return Container(
      color: Colors.blue,
      height: 40,
      width: 80,
      child: GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: () {
          context.read<Counter>().set(0);
          print('WidgetChild0');
        },
        child: Center(
          child: Text(
            '${context.watch<Counter>().count}',
            style: TextStyle(color: Colors.white),
          ),
        ),
      ),
    );
  }
}

widget_child1.dart

import 'package:untitled1/counter.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class WidgetChild1 extends StatelessWidget {
  const WidgetChild1({Key? key}) : super(key: key);

  Widget build(BuildContext context) {
    return Container(
      color: Colors.blue,
      height: 40,
      width: 80,
      child: GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: () {
          context.read<Counter>().set(1);
          print('WidgetChild1');
        },
        child: Center(
          child: Text(
            '${context.watch<Counter>().count}',
            style: TextStyle(color: Colors.white),
          ),
        ),
      ),
    );
  }
}

main.dart

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ChangeNotifierProvider(
        create: (_) => Counter(),
        child: const MyHomePage(title: 'Flutter Demo Home Page'),
      ),
      //home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
  Widget build(BuildContext context) {
    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(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          // children: const [],
          children: const [WidgetChild0(), WidgetChild1()],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          context.read<Counter>().increment();
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

provide   使用注意细节:

也是共享的数据需要放在 父节点中; 再共有的父节点中 都可以对 数据进行修改更新; 实现双向动态数据: 调用

notifyListeners

其中 MultiProvider,Consumer 适合多组 ChangeNotifier ;以实现解耦操作;基本用法和ChangeNotifierProvider 相同;详细可参考:https://johns.blog.csdn.net/article/details/122139508https://johns.blog.csdn.net/article/details/122139508

猜你喜欢

转载自blog.csdn.net/nicepainkiller/article/details/129235765