【问题标题】:How to force stateful widget redraw using keys?如何使用键强制有状态小部件重绘?
【发布时间】:2021-06-03 21:54:12
【问题描述】:

我正在制作一个从 API 中提取数据并将其显示在视图中的应用(MVC 样式)。
我需要弄清楚如何强制我的视图小部件重新绘制自己。现在我尝试使用 ValueKeys 和 ObjectKeys 但无济于事。

代码很多很多,所以我将尽可能使用 sn-ps 以保持清晰。 (如果您需要查看更多代码,请随时询问)

这是我的视图小部件:

class view extends StatefulWidget{

  view({
    Key key,
    this.count = 0,
  }) : super(key: key);
  int count;
  String _action='';
  var _actionParams='';
  var _data;
  Function(String) callback;

  void setAction(String newAction){
    _action = newAction;
  }

  void setActionParams(String params){
    _actionParams = jsonDecode(params);
  }

  void setData(String data){
    _data = jsonDecode(data);
  }

  void incrementCounter(){
    count++;
  }

  @override
  _viewState createState() => _viewState();
}
class _viewState extends State<view>{
  Object redrawObject = Object();

  @override
  Widget build(BuildContext context) {
    /*
    switch(widget._action){
      case '':
        break;
      default:
        return null;
    }
    */
     return Text("Counter: "+widget.count.toString());
  }
  @override
  void initState(){
    this.redrawObject = widget.key;
    super.initState();
  }
}

您可以在注释代码中看到,我计划根据传递给它的数据更改视图构建自身的方式。

到目前为止,我尝试的是在构造函数中从 main.dart 将 ValueKey/ObjectKey 传递给视图,然后在运行时更改对象。不幸的是,这不起作用。

在我的 main.dart 顶部(可从 main 中的任何位置访问)我有这个:

Object redraw = Object();
final dataView = new view(key: ObjectKey(redraw));

然后在主页的正文中,我在下方有一个视图和一个浮动按钮。 如果我按下按钮,它应该增加视图内的计数器并强制它重绘。这是我到目前为止尝试过的代码:

body: Center(
        child: dataView
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.badge),
        onPressed: (){
          dataView.incrementCounter();
          redraw = new Object();
        },
      ),

据我了解,如果用作键的对象发生更改,则颤动应该重建小部件的状态。所以我将我的对象设置为一个新对象,但它不起作用。

我也试过这样的:

onPressed: (){
          setState((){
            dataView.incrementCounter();
            redraw = new Object();
          });
        },

最终我想将导航器与我的视图小部件结合使用(以便我们有一个后退按钮),但我不知道这是否可行。

感觉有点像我在与框架作斗争。我应该使用不同的范例吗(比如页面?)或者我可以这样做吗?

如何强制我的视图小部件重新绘制?

【问题讨论】:

    标签: flutter dart mobile


    【解决方案1】:

    你可以check flutter_phoenix的逻辑重绘效果。我认为它非常有用,或者您可以只使用包本身。基本上它可以满足您的要求。

    它在状态中创建一个唯一的键。

     Key _key = UniqueKey();
    

    将其注入容器。

    @override
      Widget build(BuildContext context) {
        return Container(
          key: _key,
          child: widget.child,
        );
      }
    

    当你调用 rebirth 时,它只是刷新键,这会导致视图重建。

    void restartApp() {
        setState(() {
          _key = UniqueKey();
        });
      }
    

    【讨论】:

    • 这是一个不错的解决方案。我试图在不使用 phoenix 库的情况下遵循 git 上的代码,但是当我尝试调用 rebirth/refresh 时它给了我一条错误消息。它说:“在 null 上调用了方法重绘”。我正在使用脚手架上下文从我的脚手架调用重生/刷新。不可为空的安全性现在也不起作用。有什么想法吗?
    【解决方案2】:

    使用 Göktuğ Vatandaş 的答案和 GlobalKeys 我能够弄清楚。

    我在 state 中创建了一个 reDraw() 函数,然后我使用 GlobalKey 从我的 main 调用它。

    注意:包装在容器中并为容器使用密钥不是必需的。调用 setState() 足以强制重绘。

    这是新的视图小部件:

    import 'dart:convert';
    
    import 'package:flutter/cupertino.dart';
    
    GlobalKey<_viewState> viewKey = GlobalKey();
    
    class view extends StatefulWidget{
    
      view({
        Key key,
        this.count = 0,
      }) : super(key: key);
      int count;
      String _action='';
      var _actionParams='';
      var _data;
      Function(String) callback;
    
      void setAction(String newAction){
        _action = newAction;
      }
    
      void setActionParams(String params){
        _actionParams = jsonDecode(params);
      }
    
      void setData(String data){
        _data = jsonDecode(data);
      }
    
      void incrementCounter(){
        count++;
      }
    
      @override
      _viewState createState() => _viewState();
    
    }
    class _viewState extends State<view>{
    
      @override
      Widget build(BuildContext context) {
        /*
        switch(widget._action){
          case '':
            break;
          default:
            return null;
        }
        */
        return Text("Counter: "+widget.count.toString());
      }
      @override
      void initState(){
        super.initState();
      }
    
      void reDraw(){
        setState((){});
      }
    }
    

    这是我在 main 中声明视图小部件的地方:

    final dataView = new view(key: viewKey);
    

    这里是我调用 reDraw() 函数的地方:

    floatingActionButton: FloatingActionButton(
            child: Icon(Icons.badge),
            onPressed: (){
              dataView.incrementCounter();
              viewKey.currentState.reDraw();
            },
          ),
    

    感谢 Göktuğ Vatandaş!

    【讨论】:

      猜你喜欢
      • 2017-10-02
      • 2013-11-15
      • 1970-01-01
      • 2021-11-01
      • 2021-03-05
      • 2021-12-24
      • 2021-09-21
      • 1970-01-01
      • 2021-02-16
      相关资源
      最近更新 更多