无需重新构建父级子控件的Flutter setState

JWR*_*ich 1 android dart flutter

我有一个包含a listView和a 的父对象,floatingActionButton我想floatingActionButton在用户开始滚动时隐藏,我设法在父窗口小部件中做到这一点,但这需要每次重新构建列表。

我已经将其floatingActionButton移至单独的类,因此我可以更新状态并仅重建该小部件,因为我遇到的问题是将数据从ScrollController父类中的数据传递给孩子,这在通过导航进行操作时很简单,但是接缝却更多笨拙而不重建父母!

bof*_*mer 13

为了获得最佳性能,您可以创建自己的包装器Scaffold,将body用作参数。在body当小部件将无法重建setState被调用HideFabOnScrollScaffoldState

这是一个常见的模式,也可以在核心小部件中找到,例如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,
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

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


Dav*_*ees 6

I think using a stream is more simpler and also pretty easy.

You just need to post to the stream when your event arrives and then use a stream builder to respond to those changes.

Here I am showing/hiding a component based on the focus of a widget in the widget hierarchy.

I've used the rxdart package here but I don't believe you need to. also you may want to anyway because most people will be using the BloC pattern anyway.

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();
            }),
          )
        ],
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我很难理解流构建器。你的答案非常简单易懂。非常感谢。 (2认同)

Tom*_*ers 6

当父级中的值发生变化时,一种重建子级小部件的好方法是使用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();
  }
}

Run Code Online (Sandbox Code Playgroud)

  • 这应该是新接受的答案。这正是我们所需要的。 (2认同)

Bik*_*ram 5

您可以使用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++;
                    });
                  })
            ],
          );
        }),
      ],
    );
  }
}
Run Code Online (Sandbox Code Playgroud)