繁体   English   中英

Flutter setState 的子部件而不重建父部件

[英]Flutter setState of child widget without rebuilding parent

我有一个包含父listViewfloatingActionButton我想隐藏floatingActionButton当用户开始滚动我设法父窗口部件内做到这一点,但是这需要每次要重建的名单。

我提出floatingActionButton到一个单独的类,所以我可以更新状态,只有重建插件我遇到的问题是,从过往的数据ScrollController在父类中的孩子,这是简单的通过导航,但接缝一个这样做时,它但是不重建父级更尴尬!

为了获得最佳性能,您可以围绕Scaffold创建自己的包装器,将body作为参数。 HideFabOnScrollScaffoldState调用setState时,将不会重建body小部件。

这是一种常见的模式,也可以在核心小部件(例如AnimationBuilder

import 'package:flutter/material.dart';

main() => runApp(MaterialApp(home: MyHomePage()));

class MyHomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  ScrollController controller = ScrollController();

  @override
  Widget build(BuildContext context) {
    return HideFabOnScrollScaffold(
      body: ListView.builder(
        controller: controller,
        itemBuilder: (context, i) => ListTile(title: Text('item $i')),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        child: Icon(Icons.add),
      ),
      controller: controller,
    );
  }
}

class HideFabOnScrollScaffold extends StatefulWidget {
  const HideFabOnScrollScaffold({
    Key key,
    this.body,
    this.floatingActionButton,
    this.controller,
  }) : super(key: key);

  final Widget body;
  final Widget floatingActionButton;
  final ScrollController controller;

  @override
  State<StatefulWidget> createState() => HideFabOnScrollScaffoldState();
}

class HideFabOnScrollScaffoldState extends State<HideFabOnScrollScaffold> {
  bool _fabVisible = true;

  @override
  void initState() {
    super.initState();
    widget.controller.addListener(_updateFabVisible);
  }

  @override
  void dispose() {
    widget.controller.removeListener(_updateFabVisible);
    super.dispose();
  }

  void _updateFabVisible() {
    final newFabVisible = (widget.controller.offset == 0.0);
    if (_fabVisible != newFabVisible) {
      setState(() {
        _fabVisible = newFabVisible;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: widget.body,
      floatingActionButton: _fabVisible ? widget.floatingActionButton : null,
    );
  }
}

或者,您也可以为FloatingActionButton创建一个包装器,但这可能会破坏过渡。

我认为使用流更简单,也很容易。

您只需要在事件到达时发布到流,然后使用流构建器来响应这些更改。

在这里,我根据小部件层次结构中小部件的焦点显示/隐藏组件。

我在这里使用了 rxdart 包,但我认为您不需要。 你也可能想要,因为大多数人无论如何都会使用 BloC 模式。

import 'dart:async';
import 'package:rxdart/rxdart.dart';

class _PageState extends State<Page> {
  final _focusNode = FocusNode();

  final _focusStreamSubject = PublishSubject<bool>();
  Stream<bool> get _focusStream => _focusStreamSubject.stream;

  @override
  void initState() {
    super.initState();

    _focusNode.addListener(() {
      _focusStreamSubject.add(_focusNode.hasFocus);
    });
  }

  @override
  void dispose() {
    _focusNode.dispose();
    super.dispose();
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: <Widget>[
          _buildVeryLargeComponent(),
          StreamBuilder(
            stream: _focusStream,
            builder: ((context, AsyncSnapshot<bool> snapshot) {
              if (snapshot.hasData && snapshot.data) {
                return Text("keyboard has focus")
              }
              return Container();
            }),
          )
        ],
      ),
    );
  }
}

您可以使用StatefulBuilder并使用其 setState 函数在其下构建小部件。

例子:

import 'package:flutter/material.dart';

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {

  int count = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // put widget here that you do not want to update using _setState of StatefulBuilder
        Container(
          child: Text("I am static"),
        ),
        StatefulBuilder(builder: (_context, _setState) {
          // put widges here that you want to update using _setState
          return Column(
            children: [
              Container(
                child: Text("I am updated for $count times"),
              ),
              RaisedButton(
                  child: Text('Update'),
                  onPressed: () {
                    // Following only updates widgets under StatefulBuilder as we are using _setState
                    // that belong to StatefulBuilder
                    _setState(() {
                      count++;
                    });
                  })
            ],
          );
        }),
      ],
    );
  }
}

当父级中的值发生变化时,一种重建子级小部件的好方法是使用ValueNotifierValueListenableBuilder ValueNotifier的实例添加到父级的状态类,并将要重建的小部件包装在ValueListenableBuilder

当您想要更改该值时,请使用通知程序而不调用setState进行更改,并且子小部件会使用新值重建。

import 'package:flutter/material.dart';

class Parent extends StatefulWidget {
  @override
  _ParentState createState() => _ParentState();
}

class _ParentState extends State<Parent> {
  ValueNotifier<bool> _notifier = ValueNotifier(false);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(onPressed: () => _notifier.value = !_notifier.value, child: Text('toggle')),
        ValueListenableBuilder(
            valueListenable: _notifier,
            builder: (BuildContext context, bool val, Widget child) {
              return Text(val.toString());
            }),
      ],
    );
  }

  @override
  void dispose() {
      _notifier.dispose();

      super.dispose();
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM