代码之家  ›  专栏  ›  技术社区  ›  Andrea Grippi

颤振中tabview的动态子项

  •  1
  • Andrea Grippi  · 技术社区  · 8 年前

    我正在尝试构建一个有列表的选项卡视图。

    类别标签和列表内容都将从数据库中提取。

    我正在从调用方页面传递标签,并成功地将它们作为列表传递。 现在我试图加载我的列表,我已经构建了一个小部件(mylist),它成功地返回了一个未来的列表视图。

    问题有两个:

    1. 每次我向左或向右滑动时,列表都会自动重建,而我只希望创建一次
    2. 我如何使用我所做的代码,让标签的子标签实际反映标签,并根据我有多少类别加载数据?

    现在我的代码是:

    import 'package:flutter/material.dart';
    import 'package:flutter_app/ui/menu_category_list.dart';
    
    // Each TabBarView contains a _Page and for each _Page there is a list
    // of _CardData objects. Each _CardData object is displayed by a _CardItem.
    
    List<Tab> Tabs(List<String> l){
      List<Tab> list;
      for (String c in l) {
        list.add(new Tab(text: c));
      }
      return list;
    }
    
    
    
    class TabsDemo extends StatelessWidget {
    
      const TabsDemo({ Key key , this.categorie}) : super(key: key);
    
      final List<Tab> categorie;
    
      @override
      Widget build(BuildContext ctxt) {
        return new MaterialApp(
          title: "Nice app",
          home: new DefaultTabController(
          length: 5,
          child: new Scaffold(
            appBar: new AppBar(
              title: new Text("Title"),
              bottom: new TabBar(
                tabs:
                  categories,
                  //new Tab(text: "First Tab"),
                  //new Tab(text: "Second Tab"),
    
              ),
    
            ),
            body: new TabBarView(
                children: [
                  new MenuCategoryList(),
                  new MenuCategoryList(),
                  new MenuCategoryList(),
                  new MenuCategoryList(),
                  new MenuCategoryList()
                ]
            )
          ),
        )
        );
      }
    }
    

    currently result

    提前多谢了

    2 回复  |  直到 8 年前
        1
  •  4
  •   Chaythanya Nair    8 年前

    你可以用 List<E>.generate 为了达到这个目的。

    import 'package:flutter/material.dart';
    

    假设您有一组类别从呼叫者页面传递。假设这是你的分类列表。

    List<String> categories = ["a", "b", "c", "d", "e", "f", "g", "h"];
    

    然后你可以做这样的事情来实现你的愿望。

    class TabsDemo extends StatefulWidget {
      @override
      _TabsDemoState createState() => _TabsDemoState();
    }
    
    class _TabsDemoState extends State<TabsDemo> {
      TabController _controller;
    
      @override
      void initState() {
        super.initState();
      }
    
        @override
        Widget build(BuildContext ctxt) {
          return new MaterialApp(
            home: DefaultTabController(
                length: categories.length,
                child: new Scaffold(
                  appBar: new AppBar(
                    title: new Text("Title"),
                    bottom: new TabBar(
                      isScrollable: true,
                        tabs: List<Widget>.generate(categories.length, (int index){
                      print(categories[0]);
                      return new Tab(icon: Icon(Icons.directions_car), text: "some random text");
    
                    }),
    
                  ),
                ),
    
            body: new TabBarView(
                 children: List<Widget>.generate(categories.length, (int index){
                    print(categories[0]);
                    return new Text("again some random text");
    
                 }),
              )
           ))
          );
      }
    

    您还可以将不同的小部件集设置为选项卡视图。您可以创建一个页面列表并遵循相同的方法。

        2
  •  3
  •   Yuriy Luchaninov    7 年前

    绝对正确 List<E>.generate 最佳解决方案。

    如果需要修改数组,就会出现问题。它们包含这样一个事实:当修改一个数组时,您没有机会使用同一个控制器。

    enter image description here

    在这种情况下,您可以使用下一个自定义小部件:

    import 'package:flutter/material.dart';
    
      void main() => runApp(MyApp());
    
      class MyApp extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            title: 'Flutter Demo',
            home: MyHomePage(),
          );
        }
      }
    
      class MyHomePage extends StatefulWidget {
        @override
        _MyHomePageState createState() => _MyHomePageState();
      }
    
      class _MyHomePageState extends State<MyHomePage> {
        List<String> data = ['Page 0', 'Page 1', 'Page 2'];
        int initPosition = 1;
    
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            body: SafeArea(
              child: CustomTabView(
                initPosition: initPosition,
                itemCount: data.length,
                tabBuilder: (context, index) => Tab(text: data[index]),
                pageBuilder: (context, index) => Center(child: Text(data[index])),
                onPositionChange: (index){
                  print('current position: $index');
                  initPosition = index;
                },
                onScroll: (position) => print('$position'),
              ),
            ),
            floatingActionButton: FloatingActionButton(
              onPressed: () {
                setState(() {
                  data.add('Page ${data.length}');
                });
              },
              child: Icon(Icons.add),
            ),
          );
        }
      }
    
      /// Implementation
    
      class CustomTabView extends StatefulWidget {
        final int itemCount;
        final IndexedWidgetBuilder tabBuilder;
        final IndexedWidgetBuilder pageBuilder;
        final Widget stub;
        final ValueChanged<int> onPositionChange;
        final ValueChanged<double> onScroll;
        final int initPosition;
    
        CustomTabView({
          @required this.itemCount,
          @required this.tabBuilder,
          @required this.pageBuilder,
          this.stub,
          this.onPositionChange,
          this.onScroll,
          this.initPosition,
        });
    
        @override
        _CustomTabsState createState() => _CustomTabsState();
      }
    
      class _CustomTabsState extends State<CustomTabView> with TickerProviderStateMixin {
        TabController controller;
        int _currentCount;
        int _currentPosition;
    
        @override
        void initState() {
          _currentPosition = widget.initPosition ?? 0;
          controller = TabController(
            length: widget.itemCount,
            vsync: this,
            initialIndex: _currentPosition,
          );
          controller.addListener(onPositionChange);
          controller.animation.addListener(onScroll);
          _currentCount = widget.itemCount;
          super.initState();
        }
    
        @override
        void didUpdateWidget(CustomTabView oldWidget) {
          if (_currentCount != widget.itemCount) {
            controller.animation.removeListener(onScroll);
            controller.removeListener(onPositionChange);
            controller.dispose();
    
            if (widget.initPosition != null) {
              _currentPosition = widget.initPosition;
            }
    
            if (_currentPosition > widget.itemCount - 1) {
                _currentPosition = widget.itemCount - 1;
                _currentPosition = _currentPosition < 0 ? 0 : 
                _currentPosition;
                if (widget.onPositionChange is ValueChanged<int>) {
                   WidgetsBinding.instance.addPostFrameCallback((_){
                    if(mounted) {
                      widget.onPositionChange(_currentPosition);
                    }
                   });
                }
             }
    
            _currentCount = widget.itemCount;
            setState(() {
              controller = TabController(
                length: widget.itemCount,
                vsync: this,
                initialIndex: _currentPosition,
              );
              controller.addListener(onPositionChange);
              controller.animation.addListener(onScroll);
            });
          } else if (widget.initPosition != null) {
            controller.animateTo(widget.initPosition);
          }
    
          super.didUpdateWidget(oldWidget);
        }
    
        @override
        void dispose() {
          controller.animation.removeListener(onScroll);
          controller.removeListener(onPositionChange);
          controller.dispose();
          super.dispose();
        }
    
        @override
        Widget build(BuildContext context) {
          if (widget.itemCount < 1) return widget.stub ?? Container();
    
          return Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              Container(
                alignment: Alignment.center,
                child: TabBar(
                  isScrollable: true,
                  controller: controller,
                  labelColor: Theme.of(context).primaryColor,
                  unselectedLabelColor: Theme.of(context).hintColor,
                  indicator: BoxDecoration(
                    border: Border(
                      bottom: BorderSide(
                        color: Theme.of(context).primaryColor,
                        width: 2,
                      ),
                    ),
                  ),
                  tabs: List.generate(
                    widget.itemCount,
                        (index) => widget.tabBuilder(context, index),
                  ),
                ),
              ),
              Expanded(
                child: TabBarView(
                  controller: controller,
                  children: List.generate(
                    widget.itemCount,
                        (index) => widget.pageBuilder(context, index),
                  ),
                ),
              ),
            ],
          );
        }
    
        onPositionChange() {
          if (!controller.indexIsChanging) {
            _currentPosition = controller.index;
            if (widget.onPositionChange is ValueChanged<int>) {
              widget.onPositionChange(_currentPosition);
            }
          }
        }
    
        onScroll() {
          if (widget.onScroll is ValueChanged<double>) {
            widget.onScroll(controller.animation.value);
          }
        }
      }