【问题标题】:Animating between provider stream changes提供程序流更改之间的动画
【发布时间】:2021-04-14 12:35:54
【问题描述】:

我有 5 个页面的综合浏览量,每个页面都有自己的脚手架。所有状态都通过流或值的提供者进行管理。我有一个流,它有自己的内置方法,可以通过 InternetConnected.connected 或断开连接。当互联网连接丢失时,我想在特定页面中加载一个单独的 UI,显示互联网连接丢失,而不是之前存在于脚手架中的小部件。

我现在是怎么做的(伪代码):

class ConnectionScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
  final connection = Provider.of<InternetStatus>(context);

  detectConnection () {
  if (connection.InternetConnection == InternetConnection.connected)
      return Container(); // Returns UI when internet on
  else 
      return Container(); // Returns disconnected UI
  }

  return Scaffold(body: detectConnection());
}

两个问题:

  1. 我想为两种状态之间的过渡制作动画,即。 Connected 和 Disconnected 断开连接屏幕从显示屏顶部向下流动,反之亦然。提供者状态管理的正确方法是什么?现在它只是瞬间重建,这不是很“漂亮”。

  2. 由于 Provider.of 不允许在流值更改的情况下进行粒度重建,我将如何使其更好地处理提供者“提供”的其他属性?我知道 Consumer 和 Selector,但它们也在重建 UI...

提前致谢

【问题讨论】:

    标签: flutter dart flutter-provider


    【解决方案1】:

    动画

    AnimatedSwitcher 小部件(包含在 SDK 中,与 Provider 无关)可能足以在显示连接/断开状态的两个小部件之间进行动画处理。 (如果您只是在 Container 的构造函数参数列表中切换颜色或其他内容,AnimatedContainer 也可以工作。)

    AnimatedSwitcher 的孩子需要 key,当孩子属于同一班级但内部不同时。如果它们是完全不同的 Type,Flutter 知道在两者之间进行动画处理,但如果它们是相同的 Type,则不会。 (与 Flutter 如何分析小部件树以寻找所需的重建有关。)

    仅重建受影响的小部件

    在下面的示例中,YellowWidget 没有被重建,它的父级也没有。在示例中从已连接状态更改为已断开连接状态时,仅重建 Consumer&lt;InternetStatus&gt; 小部件。

    我不是 Provider 方面的专家,我发现在知道使用哪个 Provider/Consumer/Selector/watcher 以避免不必要的重建时很容易出错。如果 Provider 没有为您点击,您可能对 GetRxDart+GetIt 等其他状态管理解决方案感兴趣。

    注意:额外的 Builder 小部件用作 ChangeNotifierProvider 子级的父级,以使所有内容都位于子级之下。这允许 InheritedWidget 按预期运行(构建 Provider 的基础)。否则,ChangeNotifierProvider 的子节点实际上将共享其上下文并成为其兄弟,而不是后代。

    即他们都会得到这里显示的上下文:

    class ProviderGranularPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
    

    这也是 Flutter 的一个微妙之处。如果你wrap your entire MaterialApp or MyApp widget in Provider,这个额外的Builder显然是没有必要的。

    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    
    class InternetStatus extends ChangeNotifier {
      bool connected = true;
    
      void setConnect(bool _connected) {
        connected = _connected;
        notifyListeners();
      }
    }
    
    /// Granular rebuilds using Provider package
    class ProviderGranularPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider<InternetStatus>(
          create: (_) => InternetStatus(),
          child: Builder(
            builder: (context) {
              print('Page (re)built');
              return SafeArea(
                child: Scaffold(
                  body: Column(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [
                      Expanded(
                        flex: 3,
                        child: Consumer<InternetStatus>(
                          builder: (context, inetStatus, notUsed) {
                            print('status (re)built');
                            return AnimatedSwitcher(
                              duration: Duration(seconds: 1),
                              child: Container(
                                  key: getStatusKey(context),
                                  alignment: Alignment.center,
                                  color: getStatusColor(inetStatus),
                                  child: getStatusText(inetStatus.connected)
                              ),
                            );
                          },
                        ),
                      ),
                      Expanded(
                        flex: 3,
                        child: YellowWidget(),
                      ),
                      Expanded(
                        flex: 1,
                        child: Container(
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                            children: [
                              RaisedButton(
                                child: Text('Connect'),
                                onPressed: () => setConnected(context, true),
                              ),
                              RaisedButton(
                                child: Text('Disconnect'),
                                onPressed: () => setConnected(context, false),
                              )
                            ],
                          ),
                        ),
                      )
                    ],
                  ),
                ),
              );
            },
          ),
        );
      }
    
      /// Show other ways to access Provider State, using context & Provider.of
      Key getStatusKey(BuildContext context) {
        return ValueKey(context.watch<InternetStatus>().connected);
      }
    
      void setConnected(BuildContext context, bool connected) {
        Provider.of<InternetStatus>(context, listen: false).setConnect(connected);
      }
    
      Color getStatusColor(InternetStatus status) {
        return status.connected ? Colors.blue : Colors.red;
      }
    
      Widget getStatusText(bool connected) {
        String _text = connected ? 'Connected' : 'Disconnected';
        return Text(_text, style: TextStyle(fontSize: 25));
      }
    }
    
    class YellowWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        print('Yellow was (re)built');
        return Container(
          color: Colors.yellow,
          child: Center(
            child: Text('This should not rebuild'),
          ),
        );
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-11-08
      • 1970-01-01
      • 2013-10-18
      • 2014-08-15
      • 2021-12-22
      • 2022-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多