flutter数据监听器

Categories: flutter

最近用Flutter做功能的时候,发现了这么一个控件ValueListenableBuilder,它也是一个Widget,从它的名字看应该是监听数据,并且用新的数据生成Widget,它的参数就三个:

const ValueListenableBuilder({
    @required this.valueListenable,
    @required this.builder,
    this.child,
  }) 

参数说明

示例

从上面那些说明看来这个控件的作用就是作为局部刷新用的,可能我们整个页面上只是一个小参数变化了,那有了这个Widget就不需要用setState(() {});来刷新整个页面。

做个简单的示例,这个示例是flutter默认生成的项目改写的:

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  final ValueNotifier<int> _notifier = ValueNotifier<int>(0);

  void _incrementCounter() {
    _counter++;
    _notifier.value++;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ValueListenableBuilder(
                valueListenable: _notifier,
                builder: (BuildContext context, int value, Widget child) {
                  return Text(
                    'You have pushed the button this many times:$value',
                  );
                }),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), 
   );
  }
}

20190614-1.2019-06-14 15_36_31

_incrementCounter函数的代码,在点击按钮的时候,没有执行setState(() {});,但是ValueListenableBuilder内的Text的数字却变化了,而原来的外面的那个Text上的数字没有变化。

示例2

上面的例子监听了一个int类型,这次用一个复杂对象,顺便试试一下child参数。 先看图:

20190614-2.2019-06-14 16_04_03

复杂对象😄:

class ComplicatedObject {
  int number;
  String title;

  ComplicatedObject({this.number, this.title});
}

示例代码:

class _MyHomePageState extends State<MyHomePage> {
  final ValueNotifier<ComplicatedObject> _notifier =
      ValueNotifier<ComplicatedObject>(
          ComplicatedObject(number: 0, title: '标题'));
  //中间不变的内容
  Widget _content;

  void _incrementCounter() {
    _notifier.value = ComplicatedObject(number: 1024, title: '新标题');
  }

  @override
  void initState() {
    _content = Center(
        child: Text(
      '这里是内容。。。。。。。。。。。。。',
    ));
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ValueListenableBuilder(
        valueListenable: _notifier,
        builder: (BuildContext context, ComplicatedObject value, Widget child) {
          return Column(
            children: <Widget>[
              Container(
                height: 48,
                child: Text('${value.title}',
                    style: Theme.of(context).textTheme.display1),
              ),
              Expanded(
                child: child,
                flex: 1,
              ),
              Container(
                height: 48,
                child: Text('${value.number}',
                    style: Theme.of(context).textTheme.caption),
              ),
            ],
          );
        },
        child: _content,//这里是传入上面生成好的不变的Widget
      ),

      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

自定义监听对象属性

既然复杂对象可以监听,那肯定有些需求说是我只想监听这个对象中的某些属性怎么办,这可以通过重写ValueNotifier对象实现:

class ComplicatedObjectNotifier extends ValueNotifier<ComplicatedObject> {
  
  ComplicatedObjectNotifier(ComplicatedObject object): super(object);

  void setTitle(String newTitle) {
    value.title = newTitle;
    //这句是关键 一定要写。
    notifyListeners();
  } 

}

有了这个重写的类,把原来代码中的ValueNotifier替换掉:

class _MyHomePageState extends State<MyHomePage> {
  final ComplicatedObjectNotifier _notifier =
      ComplicatedObjectNotifier(
          ComplicatedObject(number: 0, title: '标题'));
  //中间不变的内容
  Widget _content;

  void _incrementCounter() {
    _notifier.setTitle('又是新标题');
  }

  @override
  void initState() {
    _content = Center(
        child: Text(
      '这里是内容。。。。。。。。。。。。。',
    ));
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ValueListenableBuilder(
        valueListenable: _notifier,
        builder: (BuildContext context, ComplicatedObject value, Widget child) {
          return Column(
            children: <Widget>[
              Container(
                height: 48,
                child: Text('${value.title}',
                    style: Theme.of(context).textTheme.display1),
              ),
              Expanded(
                child: child,
                flex: 1,
              ),
              Container(
                height: 48,
                child: Text('${value.number}',
                    style: Theme.of(context).textTheme.caption),
              ),
            ],
          );
        },
        child: _content,//这里是传入上面生成好的不变的Widget
      ),

      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

结果就是这样了: 20190614-3.2019-06-14 16_19_11

还是那句老话Flutter给我们提供了很多好玩好看又好用的Widget,对于一个开发者而言,真是太友好了!

The End !