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?