flutter中,通过provider状态管理,向集合里面追加项时,导致所有项都build了,如何处理?

界面如上,整个组件为Tabs,状态管理类TabsProvider,里面维护了一个集合items,表示有多少“项”,构建“项”独立成方法_buildTabItem,我的想法是,点击“增加一项”按钮时,在数组末尾追加一项,为了更好的性能,我想着只会调用一次_buildTabItem(打印build_tabs_item),但是目前的效果是,增加一项,集合中所有的“项”都会重新构建。

注:因为我看到的例子,都是修改集合中的一项,能做到只重新构建被修改的项(仅仅)。想着追加一项,也能做到相同的效果;

动态效果如如下:

代码如下:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'dart:math' as math;

class TabsProvider with ChangeNotifier {
  final List<TabItem> _items = [
    TabItem(id: 1, title: 'Tab 1'),
    TabItem(id: 2, title: 'Tab 2'),
    TabItem(id: 3, title: 'Tab 3'),
  ];

  List<TabItem> get items => List.unmodifiable(_items);

  appendItem(TabItem item) {
    _items.add(item);
    notifyListeners();
  }
}

// ignore: camel_case_types
class otherDemoIndexRoute extends StatefulWidget {
  const otherDemoIndexRoute({super.key});

  @override
  State<otherDemoIndexRoute> createState() => _otherDemoIndexRouteState();
}

// ignore: camel_case_types
class _otherDemoIndexRouteState extends State<otherDemoIndexRoute> {
  @override
  Widget build(BuildContext context) {
    print('主入口');
    return Scaffold(
      appBar: AppBar(title: Text('自定义控制器示例')),
      body: ChangeNotifierProvider(
        create: (context) => TabsProvider(),
        child: SingleChildScrollView(
          padding: const EdgeInsets.all(16.0),
          child: Tabs(),
        ),
      ),
    );
  }
}

class Tabs extends StatefulWidget {
  const Tabs({super.key});

  @override
  State<Tabs> createState() => _TabsState();
}

class _TabsState extends State<Tabs> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Selector<TabsProvider, List<TabItem>>(
          selector: (context, provider) => provider.items,
          shouldRebuild: (previous, next) {
            return previous.length != next.length;
          },
          builder: (context, tabList, child) {
            print('构建整个Tabs组件');
            List<Widget> widgets = [];
            for (var item in tabList) {
              widgets.add(_buildTabItem(context, item));
            }
            return Wrap(spacing: 10, children: [...widgets]);
          },
        ),

        Wrap(
          spacing: 10,
          children: [
            TextButton(
              onPressed: () {
                var tabsProvider = context.read<TabsProvider>();
                var list = tabsProvider.items.map((item) => item.id).toList();
                int maxValue = list.reduce(
                  (value, element) => math.max(value, element),
                );

                tabsProvider.appendItem(
                  TabItem(id: maxValue + 1, title: 'title${maxValue + 1}'),
                );
              },
              child: Text('增加一项'),
            ),
          ],
        ),
      ],
    );
  }

  /// 构建TabItem组件
  Widget _buildTabItem(BuildContext context, TabItem item) {
    print('build_tabs_item');

    return Material(
      borderRadius: BorderRadius.all(Radius.circular(8.0)),
      child: InkWell(
        mouseCursor: SystemMouseCursors.click, //forbidden 禁止点击效果
        child: Container(
          padding: const EdgeInsets.all(8.0),
          decoration: BoxDecoration(
            border: Border.all(color: Colors.blue),
            borderRadius: BorderRadius.circular(8.0),
          ),
          child: Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              Text(item.title, style: const TextStyle(color: Colors.black)),
            ],
          ),
        ),
      ),
    );
  }
}

class TabItem {
  int id;
  String title;
  TabItem({required this.id, required this.title});
}
阅读 489
1 个回答
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题