使子元素活动



我有一个代码,可用于按制造国家过滤汽车。代码的结构是这样的:我将国家名称和复选框放在标题ExpansionTile中;我将带有复选框的汽车名称放在儿童扩展tile中。这些东西。用户可以只勾选国家,也可以只勾选汽车名称(名称),或者全部勾选。

但是我想实现这样的想法:如果用户在国家名称旁边打了一个复选标记,那么汽车前面的复选框将被自动选中。与此示例中的功能类似https://medium.com/@nishsvn.dev/flutter-parent-and-child-checkboxes- part2-98ce62156004

class _FilterDialogUserState extends State<FilterDialogUser> {
Map<String, List<String>?> filters = {};
@override
void initState() {
super.initState();
filters = widget.initialState;
}
void _handleCheckFilter(bool checked, String key, String value) {
final currentFilters = filters[key] ?? [];
if (checked) {
currentFilters.add(value);
} else {
currentFilters.remove(value);
}
setState(() {
filters[key] = currentFilters;
});
}
final countries = [
Country(
name: 'Germany',
cars: [
Car(name: 'Audi'),
Car(name: 'BMW'),
Car(name: 'Volkswagen'),
],
),
Country(
name: 'Sweden',
cars: [
Car(name: 'Koenigsegg'),
Car(name: 'Polestar'),
Car(name: 'Volvo'),
],
),
Country(
name: 'Russian',
cars: [
Car(name: 'GAZ'),
Car(name: 'Lada'),
Car(name: 'ZAZ'),
],
),
];
@override
Widget build(BuildContext context) {
return SimpleDialog(
title: const Text('Filters',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontFamily: 'SuisseIntl',
)),
contentPadding: const EdgeInsets.all(16),
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
for (Country country in countries)
ExpansionTile(
tilePadding: EdgeInsets.zero,
childrenPadding: const EdgeInsets.symmetric(horizontal: 15),
title: CustomCheckboxTile(
value:
filters['country']?.contains(country.name) ?? false,
onChange: (check) =>
_handleCheckFilter(check, 'country', country.name),
label: country.name,
),
initiallyExpanded: () {
for (final Car car in country.cars) {
if (filters['cars']?.contains(car.name) ?? false) {
return true;
}
}
return false;
}(),
children: [
for (Car car in country.cars)
CustomCheckboxTile(
value: filters['cars']?.contains(car.name) ?? false,
onChange: (check) =>
_handleCheckFilter(check, 'cars', car.name),
label: car.name,
)
])
]),
........

如果你需要额外的代码来帮助解决这个问题,请告诉我。

您需要连接Country复选框之间的关系和Car复选框。在代码中最直接的方法是更新_handleCheckFilter的函数。它需要一些额外的信息来更新过滤器。

我把它分成两个函数:_handleCountryCheckFilter_handleCarCheckFilter:

_handleCountryCheckFilter

void _handleCountryCheckFilter(
bool checked, String country, List<String> cars) {
final countryFilters = filters['country'] ?? [];
final carFilters = filters['cars'] ?? [];
if (checked) {
countryFilters.add(country);
for (var car in cars) {
if (!carFilters.contains(car)) {
carFilters.add(car);
}
}
} else {
countryFilters.remove(country);
for (var car in cars) {
if (carFilters.contains(car)) {
carFilters.remove(car);
}
}
}
setState(() {
filters['country'] = countryFilters;
filters['cars'] = carFilters;
});
}

_handleCarCheckFilter

void _handleCarCheckFilter(
bool checked, String car, String country, List<String> cars) {
final countryFilters = filters['country'] ?? [];
final carFilters = filters['cars'] ?? [];
if (checked) {
carFilters.add(car);
var carIsFull = true;
for (var car in cars) {
if (!carFilters.contains(car)) {
carIsFull = false;
}
}
if (carIsFull && !countryFilters.contains(country)) {
countryFilters.add(country);
}
} else {
carFilters.remove(car);
var carIsEmpty = true;
for (var car in cars) {
if (carFilters.contains(car)) {
carIsEmpty = false;
}
}
if (carIsEmpty) {
countryFilters.remove(country);
}
}
setState(() {
filters['country'] = countryFilters;
filters['cars'] = carFilters;
});
}
最后,您可以更改onChange你的CustomCheckboxTile:
// country checkbox
CustomCheckboxTile(
value: filters['country']?.contains(country.name) ?? false,
onChange: (check) => _handleCountryCheckFilter(check,country.name,country.cars.map((car) => car.name).toList()),
label: country.name,
),
...
// country checkbox
CustomCheckboxTile(
value: filters['cars']?.contains(car.name) ?? false,
onChange: (check) => _handleCarCheckFilter(check,car.name,country.name,country.cars.map((car) => car.name).toList()),
label: car.name,
)

试试这个,我希望它对你有用。

@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
for (Country country in countries)
ExpansionTile(
tilePadding: EdgeInsets.zero,
childrenPadding: const EdgeInsets.symmetric(horizontal: 15),
title: CheckboxListTile(
value:
getCountryValue(country),

onChanged: (check) =>
onCountrySelected(check!, country),
title: Text(country.name!),
),
initiallyExpanded: () {
return false;
}(),
children: [
for (Car car in country.cars!)
CheckboxListTile(
value: selectedCar.contains(car),
onChanged: (check) =>
_handleCheckFilter(check!, 'cars', car),
title: Text(car.name!),
)
])
]),
),
);
}



List<Car> selectedCar = [];

void _handleCheckFilter(bool checked, String key, Car car) {
if (checked) {
selectedCar.add(car);
} else {
selectedCar.remove(car);
}
setState(() {
});
}

onCountrySelected(bool checked, Country country) {
if (checked) {
country.cars!.forEach((element) {
if (!selectedCar.contains(element)) {
selectedCar.add(element);
}
});
} else {
country.cars!.forEach((element) {
selectedCar.remove(element);
});
}
setState(() {

});
}

bool getCountryValue(Country country) {
bool selected = country.cars!.where((element) => selectedCar.contains(element)).length == country.cars!.length;
return selected;
}

List<Country> countries = [
Country(
name: 'Germany',
cars: [
Car(name: 'Audi'),
Car(name: 'BMW'),
Car(name: 'Volkswagen'),
],
),
Country(
name: 'Sweden',
cars: [
Car(name: 'Koenigsegg'),
Car(name: 'Polestar'),
Car(name: 'Volvo'),
],
),
Country(
name: 'Russian',
cars: [
Car(name: 'GAZ'),
Car(name: 'Lada'),
Car(name: 'ZAZ'),
],
),
];
}

试试这个。它会保持状态

class _FilterDialogUserState extends State<FilterDialogUser> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;

@override
Widget build(BuildContext context) {
super.build(context);
}
}

最新更新