0

for example: I have a list, when I modify an item in the list, only the modified item is rebuilt, when I append an item, the list rebuilds the newly added item, not all items in the entire list are rebuilt. When I toggle the selection, I also want to just rebuild the item that needs to be changed.

Click on the image to view the demo

environment:
  sdk: ^3.7.0
provider: ^6.1.4

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

class TabsProvider with ChangeNotifier {
  int _checkedId = 1;
  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);
  int get currentCheckedId => _checkedId;

  changeCheckedId(int id) {
    _checkedId = id;
    notifyListeners();
  }

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

  itemIncreasing(int id) {
    final index = _items.indexWhere((element) => element.id == id);
    if (index != -1) {
      // 创建新的 item 实例以确保触发更新
      _items[index] = TabItem(
        id: _items[index].id,
        title: _items[index].title,
        total: _items[index].total + 1,
      );
      notifyListeners(); // 确保调用这个方法
    }
  }

  removeItem(int id) {
    _items.removeWhere((element) => element.id == id);
    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
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    print('主入口');
    return Scaffold(
      appBar: AppBar(title: Text('provider 管理集合实例')),
      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: [
        Center(
          child: Selector<TabsProvider, int>(
            selector: (context, provider) => provider.currentCheckedId,
            builder: (context, currId, child) {
              var text = 'The current selection is:${currId.toString()}';
              print(text);
              return Text(text);
            },
          ),
        ),

        Selector<TabsProvider, List<TabItem>>(
          selector: (context, provider) => provider.items,
          // shouldRebuild: (previous, next) {
          //   return previous.length != next.length;
          // },
          builder: (context, tabList, child) {
            print('build——selector');
            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('Add item'),
            ),

            TextButton(
              onPressed: () {
                context.read<TabsProvider>().itemIncreasing(1);
              },
              child: Text('Fisrt item +1'),
            ),
          ],
        ),
      ],
    );
  }

  /// 构建TabItem组件
  Widget _buildTabItem(BuildContext context, TabItem item) {
    final tabsProvider = context.read<TabsProvider>();

    return Selector<TabsProvider, int>(
      selector: (context, provider) => provider.currentCheckedId,
      builder: (context, currId, child) {
        print('build_tabitem');

        return Material(
          color: currId == item.id ? Colors.red[100] : Colors.transparent,
          borderRadius: BorderRadius.all(Radius.circular(8.0)),
          child: InkWell(
            mouseCursor: SystemMouseCursors.click, //forbidden 禁止点击效果
            onTap: () {
              tabsProvider.changeCheckedId(item.id);
            },
            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}--${item.total}',
                    style: const TextStyle(color: Colors.black),
                  ),
                ],
              ),
            ),
          ),
        );
      },
    );
  }
}

class TabItem {
  int id;
  String title;
  int total;
  TabItem({required this.id, required this.title, this.total = 0});
}

How can I switch items, change items, or add new items, and only rebuild the corresponding items, instead of the entire tabs component?

2
  • '''How can I switch items, change items, or add new items, and only rebuild the corresponding items, instead of the entire tabs component?''' - check ValueListenableBuilder Commented May 9 at 4:12
  • Thank you for your help. I'll give it a try! Commented May 9 at 6:10

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.