首页 文章

Flutter - 使用具有动态Tab视图的TabBarView小部件实现导航抽屉

提问于
浏览
3

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

我有一个带有 Drawer widget 的Flutter应用程序 . 我正在使用这个小部件制作 Navigation drawerDrawer 有一个 ListView 作为孩子,而 ListView 包含用户可以选择的视图选项(A,B和C) .

由于应用程序的主页面( MyHomePage )从_323049延伸到我加载新视图的唯一方法是调用 setState 方法来分配我的"control variable"( viewName )的新值,然后我希望Flutter执行 Widget build(BuildContext context) MyHomePage 的方法,但这次使用 viewName 的新值 .

所有上述工作都按预期工作,问题是在 Scaffoldbody 字段中我有一个 TabBarView 小部件,因为我想向用户显示每个视图有两个选项卡( Tab 1Tab 2 )的视图( A, B and C ) .

TabBarView 孩子是:

-A StatefulTab Tab 1 的对象

  • 一个简单的 Center 小部件 Tab 2

我想要 demonstrate 这里是当你点击抽屉的一个选项(例如加载 B view )时 Tab 2 更改为预期值,但 Tab 1 (包含 stateful widget )在您点击任何其他值时不会更改它的值选项 Drawer

Note: I must 为3个视图使用相同的 StatefulTab 小部件以重用代码,因为3个视图的唯一值更改是 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为 Tab 1 的有状态wdiget获取新值?

有没有更好的方法来实现具有动态视图的导航抽屉?

提前致谢!

2 回答

  • 1

    对于实现TabBar和抽屉颤振为我们提供以下小部件 .

    1. TabController 2. TabBar 3. Drawer

    我发现了一个简单的demo TabBar和抽屉 .

  • 4

    我想我找到了你的问题 . 您将viewName保留为主页中的State,另外还保留在StatefulTab中 . 这不能真正起作用,因为对于StatefulTab,状态不会因为HomePage的状态发生变化而改变 . 我通过在两个构建方法中插入print语句得出了这个结论 . HomePage的构建方法根据您所需的行为进行操作(正如您在脚手架的 Headers 中看到的那样),但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可能是有益的 .

相关问题