我有一个 ListView
由几个带有尾随图标的 ListTile
组成。图标的颜色应根据用户点击从透明变为绿色。但是,UI 不会根据用户交互进行更新。
ServiceModel
是这样的。
class ProviderService extends ChangeNotifier {
final List<String> totalNames = ['Somesh', 'Tarulata', 'Indranil', 'Satyajyoti', 'Biswas', 'Sajal', 'Kumar', 'Slipa', 'Sonam', 'Neelam'];
List<String> _selectedNames = [];
List<String> get selectedNames => _selectedNames;
void updateselectedNames(String name) {
bool isExists = _selectedNames.contains(name);
if (isExists)
_selectedNames.remove(name);
else
_selectedNames.add(name);
notifyListeners();
}
}
ListView
是这样的。
class Members extends StatelessWidget {
@override
Widget build(BuildContext context) {
ProviderService plService = Provider.of<ProviderService>(context, listen: false);
return Scaffold(
body: SafeArea(
child: Selector<ProviderService, List<String>>(
selector: (_, service) => service.selectedNames,
builder: (context, selNames, child) {
if (plService.totalNames.isEmpty) return child;
return ListView.separated(
shrinkWrap: true,
itemBuilder: (context, index) {
String _name = plService.totalNames[index];
return ListTile(
title: Text('$_name'),
trailing: Icon(
Icons.check_circle,
color: selNames.contains(_name) ? Colors.lightGreen : Colors.transparent,
),
onTap: () {
plService.updateselectedNames(_name),
print(selNames);
},
);
},
separatorBuilder: (_, __) => Divider(),
itemCount: plService.totalNames.length,
);
},
child: Center(
child: Text('No names have been found', textAlign: TextAlign.center),
),
),
),
);
}
}
当然,main.dart
就是这样。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ChangeNotifierProvider(
create: (context) => ProviderService(),
child: Members(),
),
);
}
}
即使列表 selectedNames
已更新,UI 仍保持不变。这里出了什么问题?
答案 0 :(得分:0)
当您使用 Selector
时,您必须确保所选对象是不可变的。
Selector<ProviderService, List<String>>(
selector: (_, service) => service.selectedNames,
builder: (context, selNames, child) { ...},
),
builder
只会被调用一次,因为您的 selectedNames
对象始终保持不变。您正在同一数组对象中删除和添加项目。
因此,您应该在 updateselectedNames
中提供一个新数组:
void updateselectedNames(String name) {
_selectedNames = _selectedNames.contains(name)
? _selectedNames.where((item) => item != name).toList()
: [..._selectedNames, name];
notifyListeners();
}
答案 1 :(得分:0)
对于你的场景,我的方式是这样的。
class ProviderService extends ChangeNotifier {
final List<Name> totalNames = [
Name(name: 'Somesh', isTransparent: false),
Name(name: 'Tarulata', isTransparent: false),
];
List<Name> _selectedNames = [];
List<Name> get selectedNames => _selectedNames;
void updateselectedNames(int index) {
var exist = _isExist(totalNames[index]);
if(exist){
_selectedNames.remove(totalNames[index]);
} else {
_selectedNames.add(totalNames[index]);
}
totalNames[index].isTransparent = !totalNames[index].isTransparent;
notifyListeners();
}
bool _isExist(Name name) {
var filter = _selectedNames.singleWhere(
(element) => element.name == name.name,
orElse: () => null,
);
return filter != null;
}
}
class Name {
String name;
bool isTransparent;
Name({this.name, this.isTransparent});
}
并且您可以在 Selector
中为每个 ListView
使用 ListTile
Selector<ProviderService, Name>(
selector: (_, service) => service.totalNames[index],
builder: (context, name, child) {
return ListTile(
title: Text('${name.name}'),
trailing: Icon(
Icons.check_circle,
color: !name.isTransparent ? Colors.lightGreen : Colors.transparent,
),
onTap: () {
plService.updateselectedNames(index),
},
);
答案 2 :(得分:0)
你可以添加Selector的shouldRebuild参数并返回true。像这样:
Selector<ProviderService, List<String>>(
selector: (_, service) => service.selectedNames,
builder: (context, selNames, child) {...},
shouldRebuild: (previous, next) => true,
)