颤振中TabView的动态子级

时间:2018-06-30 19:27:19

标签: android ios mobile dart flutter

我正在尝试构建一个将列表作为子项的选项卡式视图。

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

我正在从呼叫者页面传递标签,并成功地将它们作为列表传递。 现在,我正在尝试加载列表,并且构建了一个小部件(myList),该小部件成功返回了Future ListView。

问题有两个:

  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

非常感谢

3 个答案:

答案 0 :(得分:3)

您可以使用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");

             }),
          )
       ))
      );
  }

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

答案 1 :(得分:2)

绝对是"servicebus_1_connectionString": { "type": "securestring", "metadata": { "description": "Azure Service Bus Connection String" } }, --- "dependsOn": [ "[resourceId('Microsoft.Web/connections', parameters('servicebus_1_Connection_Name'))]" ] }, { "type": "MICROSOFT.WEB/CONNECTIONS", "apiVersion": "2016-06-01", "name": "[parameters('servicebus_1_Connection_Name')]", "location": "westeurope", "properties": { "api": { "id": "[concat(subscription().id, '/providers/Microsoft.Web/locations/', 'westeurope', '/managedApis/', 'servicebus')]" }, "displayName": "[parameters('servicebus_1_Connection_DisplayName')]", "parameterValues": { "connectionString": "[parameters('servicebus_1_connectionString')]" } } 最好的解决方案。

如果需要修改阵列,则会出现问题。它们的事实在于,在修改数组时,您没有机会使用相同的控制器。

enter image description here

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

List<E>.generate

答案 2 :(得分:0)

空安全版本

import 'package:flutter/material.dart';

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({this.itemCount, this.tabBuilder, this.pageBuilder, this.stub,
    this.onPositionChange, this.onScroll, this.initPosition});

  @override
  _CustomTabsState createState() => _CustomTabsState();
}

class _CustomTabsState extends State<CustomTabView> with TickerProviderStateMixin {
  late TabController controller;
  late int _currentCount;
  late int _currentPosition;

  @override
  void initState() {
    _currentPosition = widget.initPosition!;
    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);
    }
  }
}