Flutter 不会使用不同的参数重建相同的小部件

Posted

技术标签:

【中文标题】Flutter 不会使用不同的参数重建相同的小部件【英文标题】:Flutter is not rebuilding same widget with different parameters 【发布时间】:2019-08-09 18:07:47 【问题描述】:

我正在使用带有类似子小部件的底部导航,其中仅更改了参数。只有当小部件属于 StatefulWidget 时才会出现问题,否则没有问题,底部导航栏中的指示正在改变,但正文没有改变。

孩子 1:

孩子 2:

实际结果:

class MyHomePage extends StatefulWidget 
MyHomePage(Key key, this.title) : super(key: key);
final String title;

@override
_MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State<MyHomePage> 
int _counter = 0;
Widget body;
@override
void initState() 
//    body = getBody(0);
super.initState();


@override
Widget build(BuildContext context) 
return Scaffold(
  appBar: AppBar(
    title: Text(widget.title),
    elevation: 0,
  ),
  body: body,
  bottomNavigationBar: BottomNavigationBar(
    currentIndex: _counter,
    onTap: (index)
      _counter = index;
      setState(() 
        body = getBody(index);
      );
    ,items: [
    BottomNavigationBarItem(icon: Icon(Icons.language),title: 
 Text('HELLO')),
    BottomNavigationBarItem(icon: Icon(Icons.security),title: 
Text('BYE'))
  ]),
 );

Widget getBody(int pos)
if(pos==0)
//      return new Mx(category: 'ALPHA',type: '@',);
  return new MyTAbs(category: 'ALPHA',type: '@',);

else
//      return new Mx(category:'BETA',type: '#',);
  return new MyTAbs(category:'BETA',type: '#',);
  
 

class Mx extends StatelessWidget
final String type,category;
Mx(this.type,this.category);
@override
Widget build(BuildContext context) 
 return new Scaffold(
  backgroundColor: getColor(),
  body: new Center(
    child: Text(category+' '+type),
  ),
 );

Color getColor()
if(category=='ALPHA')
  return Colors.red;

else
  return Colors.green;
  
 

class MyTAbs extends StatefulWidget
final String type,category;
MyTAbs(this.type,this.category);
Tabs createState() => new Tabs(title: category,type: type);

class Tabs extends State<MyTAbs>
final String title,type;
Tabs(this.title,this.type);
@override
Widget build(BuildContext context) 
// TODO: implement build
return new Scaffold(
  backgroundColor: getColor(),
  appBar: AppBar(
    title: Text(title+' '+type),
  ),
);

Color getColor()
if(title=='ALPHA')
  return Colors.red;

else
  return Colors.green;
  
 

我不能使用 statelessWidget,因为里面有一个动态标签部分。

【问题讨论】:

【参考方案1】:

通过添加新的 Key 作为参数并传递 UniqueKey 解决了这个问题 喜欢

return new MyTAbs(category: 'ALPHA',type: '@',key: UniqueKey(),);

MyTAbs 类

class MyTAbs extends StatefulWidget
  final String type,category;
  final Key key;
  MyTAbs(@required this.key,this.type,this.category);
  Tabs createState() => new Tabs(title: category,type: type,key: key);

标签类

class Tabs extends State<MyTAbs>
  final String title,type;
  final Key key;
  Tabs(this.title,this.type,@required this.key);
  @override
  @override
  Widget build(BuildContext context) 
    // TODO: implement build
    return new Scaffold(
      backgroundColor: getColor(),
      appBar: AppBar(
        title: Text(title+' '+type),
      ),
    );
  
  Color getColor()
    if(title=='ALPHA')
      return Colors.red;
    
    else
      return Colors.green;
    
  

钥匙

当小部件重建时,您可以使用键来控制框架与其他小部件匹配的小部件。默认情况下,框架会根据它们的 runtimeType 和它们出现的顺序来匹配当前和先前构建中的小部件。对于键,框架要求两个小部件具有相同的键以及相同的 runtimeType。 more in flutter docs

【讨论】:

非常感谢,今天遇到同样的问题。我想,如果其中一个参数被更改,Widget 将被重建,但不是,initState() 没有被调用。 UniqKey() 工作正常!【参考方案2】:

更改您的 Tabs 课程

class Tabs extends State<MyTAbs> 
  @override
  Widget build(BuildContext context) 
    return new Scaffold(
      backgroundColor: getColor(),
      appBar: AppBar(
        title: Text(widget.category + ' ' + widget.type),
      ),
    );
  

  Color getColor() 
    if (widget.category == 'ALPHA') 
      return Colors.red;
     else 
      return Colors.green;
    
  

State (Tabs) 仅创建一次。所以在那之后你不能用新参数调用构造函数。但是您可以访问小部件的字段

【讨论】:

【参考方案3】:

你在“MyTAbs”传递参数类中的问题

编辑后,现在可以工作了

您不需要将日期从“有状态”类传递给“状态”,只需在状态中使用“widget.parameterName”调用它 编辑后的代码:

class MyHomePage extends StatefulWidget 
  MyHomePage(Key key, this.title) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State<MyHomePage> 
  int _counter = 0;
  Widget body;
  @override
  void initState() 
//    body = getBody(0);
    super.initState();
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
        elevation: 0,
      ),
      body: body,
      bottomNavigationBar: BottomNavigationBar(
          currentIndex: _counter,
          onTap: (index)
            _counter = index;
            setState(() 
              body = getBody(index);
            );
          ,items: [
        BottomNavigationBarItem(icon: Icon(Icons.language),title:
        Text('HELLO')),
        BottomNavigationBarItem(icon: Icon(Icons.security),title:
        Text('BYE'))
      ]),
    );
  
  Widget getBody(int pos)
    if(pos==0)
//      return new Mx(category: 'ALPHA',type: '@',);
      return new MyTAbs(category: 'ALPHA',type: '@',);
    
    else

//      return new Mx(category:'BETA',type: '#',);
      return new MyTAbs(category:'BETA',type: '#',);
    
  

class Mx extends StatelessWidget
  final String type,category;
  Mx(this.type,this.category);
  @override
  Widget build(BuildContext context) 
    return new Scaffold(
      backgroundColor: getColor(),
      body: new Center(
        child: Text(category+' '+type),
      ),
    );
  
  Color getColor()
    if(category=='ALPHA')
      return Colors.red;
    
    else
      return Colors.green;
    
  

class MyTAbs extends StatefulWidget
  final String type,category;
  MyTAbs(this.type,this.category);
  Tabs createState() => new Tabs();

class Tabs extends State<MyTAbs>


  @override
  Widget build(BuildContext context) 
    print(widget.type);
// TODO: implement build
    return new Scaffold(
      backgroundColor: getColor(),
      appBar: AppBar(
        title: Text(widget.category+' '+widget.type),
      ),
    );
  
  Color getColor()
    if(widget.category=='ALPHA')
      return Colors.red;
    
    else
      return Colors.green;
    
  

【讨论】:

感谢@abdalmonem,您的回答是正确的,但在我的情况下,我正在 Tabs 类中加载选项卡,因此无法使用您的选项卡,而是添加了一个键作为参数,如上所述。你的回答对我来说是一个新信息。

以上是关于Flutter 不会使用不同的参数重建相同的小部件的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:检测任何在屏幕上不可见但在小部件树中的小部件的重建

Flutter:StreamProvider 的奇怪行为,使用不完整数据重建的小部件

Flutter Provider 重建不必要的小部件

如何创建自定义颤振 sdk 小部件,重建颤振和使用新的小部件

Flutter - 使用 MediaQuery 时防止重建

我们如何使用 Flutter 中的底部导航栏触发有状态小部件以通过导航重建自身?