我正在尝试做一个我认为非常简单的Flutter应用程序,但是我无法弄清楚我的代码出了什么问题。

我有一个带有抽屉小部件的Flutter应用程序。我正在使用此小部件来制作一个导航抽屉抽屉的 child 有一个 ListView ,而 ListView 包含用户可以选择的 View 选项(A,B和C)。

由于应用程序的主页( MyHomePage )是从 StatefulWidget 扩展而来的,因此,我要加载新 View 的唯一操作是调用 setState 方法来分配“控制变量”的新值( viewName ),那么我希望Flutter会执行 MyHomePage Widget build(BuildContext上下文)方法,但是这次使用新值 viewName

以上所有方法均按预期工作,但问题是在脚手架正文字段中,我有一个 TabBarView 小部件,因为我想向用户显示带有两个选项卡的 View (选项卡1每个 View ( A,B和C )每个 View 的选项卡2

TabBarView 子级是:

- StatefulTab 对象选项卡1

-用于的简单中心小部件Tab 2

我想在这里演示的是,当您点击抽屉的一个选项(例如,加载 B View )时,选项卡2 会按预期的值更改,但是选项卡1 (其中包含一个有状态窗口小部件),当您点击抽屉的任何其他选项时,其值不会更改

注:必须对3个 View 使用相同的 StatefulTab 小部件,以便重复使用代码,因为3个 View 的唯一更改值是 viewName 变量。

这是代码:

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_test/StatefulTab.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(viewName: 'A'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.viewName}) : super(key: key);

  final String viewName;

  @override
  _MyHomePageState createState() => new _MyHomePageState(viewName: viewName);
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  String viewName;

  _MyHomePageState({Key key, this.viewName});

  TabController controller;

  @override
  void initState() {
    super.initState();
    controller = new TabController(
      length: 2,
      vsync: this,
    );
  }

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

  @override
  Widget build(BuildContext context) {
    var tabs = <Tab>[
      new Tab(icon: new Icon(Icons.home), text: 'Tab 1'),
      new Tab(icon: new Icon(Icons.account_box), text: 'Tab 2')
    ];

    return new Scaffold(
      appBar: new AppBar(
        title: new Text(viewName),
      ),
      body: new TabBarView(controller: controller, children: <Widget>[
        new StatefulTab(viewName: viewName),
        new Center(child: new Text('This is the Tab 2 for view $viewName'))
      ]),
      bottomNavigationBar: new Material(
        color: Colors.blue,
        child: new TabBar(controller: controller, tabs: tabs),
      ),
      drawer: new Drawer(
        child: new ListView(
          children: <Widget>[
            new Padding(
              padding: new EdgeInsets.only(top: 50.0),
            ),
            new ClipRect(
              child: new Column(
                children: <Widget>[
                  new ListTile(
                    title: new Text('Tap to load view: A'),
                    onTap: () => _loadView('A', context),
                  ),
                  new ListTile(
                    title: new Text('Tap to load view: B'),
                    onTap: () => _loadView('B', context),
                  ),
                  new ListTile(
                    title: new Text('Tap to load view: C'),
                    onTap: () => _loadView('C', context),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  _loadView(String view, BuildContext context) {
    Navigator.of(context).pop();
    setState(() {
      if (view == 'A') {
        viewName = 'A';
      } else if (view == 'B') {
        viewName = 'B';
      } else if (view == 'C') {
        viewName = 'C';
      }
    });
  }
}

StatefulTab.dart
import 'package:flutter/material.dart';

class StatefulTab extends StatefulWidget {
  String viewName;

  StatefulTab({Key key, this.viewName}) : super(key: key);

  @override
  StatefulTabState createState() => new StatefulTabState(viewName: viewName);
}

class StatefulTabState extends State<StatefulTab> {
  String viewName;

  StatefulTabState({Key key, this.viewName});

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Text('This is the Tab 1 for View $viewName'),
    );
  }
}

我该如何告诉Flutter为标签1 的有状态wdiget取新值?

有没有更好的方法来实现带有动态 View 的导航抽屉?

提前致谢!

最佳答案

我想我找到了你的问题。您将viewName保留在主页中,另外还保留在StatefulTab中。这实际上是行不通的,因为对于StatefulTab,状态不会仅因为HomePage的状态发生变化而发生变化。通过在两个构建方法中插入打印语句得出了这个结论。 HomePage的构建方法根据您期望的行为(如您在支架的标题中已经看到的)起作用,但是StatefulTab的构建方法保持其状态。

进一步的调查和在不同地方的各种打印语句使我得出结论,即单击一个抽屉按钮后,不会调用StatefulTabState的构造函数。这是您的StatefulTab的工作示例:

class StatefulTab extends StatefulWidget {
  String viewName;

  StatefulTab({Key key, this.viewName}) : super(key: key);

  @override
  StatefulTabState createState() => new StatefulTabState();
}

class StatefulTabState extends State<StatefulTab> {
  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Text('This is the Tab 1 for View ${widget.viewName}'),
    );
  }
}

如有任何疑问,请随时评论。看看这个tutorial/documentation可能是有益的。

07-27 13:58