I have created reusable SwitchListTile and i am simply calling them whenever i want to use any. for example I have a custom SwitchListTile like this :
import 'package:flutter/material.dart';
class FitterItem extends StatefulWidget {
FitterItem(
{super.key,
required this.fitterValue,
required this.fitterTittle,
required this.fitterSubTit,
required this.onChange});
bool fitterValue;
final String fitterTittle;
final String fitterSubTit;
final void Function(bool newValue) onChange;
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _FitterItemState();
}
}
class _FitterItemState extends State<FitterItem> {
@override
Widget build(context) {
// TODO: implement build
return SwitchListTile(
value: widget.fitterValue,
onChanged: (newValue) {
setState(() {
widget.fitterValue = newValue;
});
},
title: Text(
widget.fitterTittle,
style: Theme.of(context)
.textTheme
.titleLarge!
.copyWith(color: Theme.of(context).colorScheme.primaryContainer),
),
subtitle: Text(
widget.fitterSubTit,
style: Theme.of(context)
.textTheme
.labelLarge!
.copyWith(color: Theme.of(context).colorScheme.primary),
),
);
}
}
And I have the Parent Class Like below:
import 'package:flutter/material.dart';
import 'package:meals/widgets/fitter_item.dart';
enum Fitter {
GlutenFree,
LactoseFree,
Vegan,
Vegetarian,
}
class FitterScreen extends StatefulWidget {
const FitterScreen({super.key});
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _FitterScreenState();
}
}
class _FitterScreenState extends State<FitterScreen> {
@override
Widget build(context) {
var _glutenFitter = false;
var _lactoseFitter = false;
var _vegeterianFitter = false;
var _veganFitter = false;
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: const Text("Fitter"),
),
body: WillPopScope(
onWillPop: () async {
Navigator.of(context).pop({
Fitter.GlutenFree: _glutenFitter,
Fitter.LactoseFree: _lactoseFitter,
Fitter.Vegan: _veganFitter,
Fitter.Vegetarian: _vegeterianFitter,
});
return false;
},
child: Column(
children: [
FitterItem(
fitterValue: _glutenFitter,
onChange: (bool newValue) {
setState(() {
_glutenFitter = newValue;
});
},
fitterTittle: "Gluten free",
fitterSubTit: "Only include Gluten free meals"),
const SizedBox(
height: 5,
),
FitterItem(
fitterValue: _lactoseFitter,
onChange: (newValue) {
setState(() {
_lactoseFitter = newValue;
});
},
fitterTittle: "Lactose free",
fitterSubTit: "Only include Lactose free meals"),
const SizedBox(
height: 5,
),
FitterItem(
fitterValue: _veganFitter,
onChange: (newValue) {
setState(() {
_veganFitter = newValue;
});
},
fitterTittle: "Vegan free",
fitterSubTit: "Only include Vegan free meals"),
const SizedBox(
height: 5,
),
FitterItem(
fitterValue: _vegeterianFitter,
onChange: (newValue) {
setState(() {
_vegeterianFitter = newValue;
});
},
fitterTittle: "Vegeterian free",
fitterSubTit: "Only include Vegeterian free meals"),
],
),
),
);
}
}
But I can't use the Updated value on the Parent class. It takes the Intilze value as false. Custom SwitchListTile changed his status well.
WillPopScope(
onWillPop: () async {
Navigator.of(context).pop({
Fitter.GlutenFree: _glutenFitter,
Fitter.LactoseFree: _lactoseFitter,
Fitter.Vegan: _veganFitter,
Fitter.Vegetarian: _vegeterianFitter,
});
return false;
},
CodePudding user response:
The problem is setting value within the state of the child FitterItem
widget, as well as having the var
s below the build
method of FitterScreen
which sets them to false each time it builds.
FitterItem
may be aStatelessWidget
onChanged
method of theSwitchListTile
should take the function passed from the parent, so it may run the function within the parent.
// this
onChanged: (newValue) {
setState(() {
widget.fitterValue = newValue;
});
},
// should be
onChanged: onChange,
- Move the variable in
FitterScreen
above the build method.
var _glutenFitter = false;
var _lactoseFitter = false;
var _vegeterianFitter = false;
var _veganFitter = false;
@override
Widget build(context) {
// ...
Full code
// start enum
enum Fitter {
GlutenFree,
LactoseFree,
Vegan,
Vegetarian,
}
/// end enum
// start FitterItem
class FitterItem extends StatelessWidget {
const FitterItem({
super.key,
required this.fitterValue,
required this.fitterTittle,
required this.fitterSubTit,
required this.onChange,
});
final bool fitterValue;
final String fitterTittle;
final String fitterSubTit;
final void Function(bool newValue) onChange;
@override
Widget build(context) {
return SwitchListTile(
value: fitterValue,
onChanged: onChange,
title: Text(
fitterTittle,
style: Theme.of(context)
.textTheme
.titleLarge!
.copyWith(color: Theme.of(context).colorScheme.primaryContainer),
),
subtitle: Text(
fitterSubTit,
style: Theme.of(context)
.textTheme
.labelLarge!
.copyWith(color: Theme.of(context).colorScheme.primary),
),
);
}
}
/// end FitterItem
// start FitterScreen
class FitterScreen extends StatefulWidget {
const FitterScreen({super.key});
@override
State<StatefulWidget> createState() => _FitterScreenState();
}
class _FitterScreenState extends State<FitterScreen> {
var _glutenFitter = false;
var _lactoseFitter = false;
var _vegeterianFitter = false;
var _veganFitter = false;
@override
Widget build(context) {
return Scaffold(
appBar: AppBar(
title: const Text("Fitter"),
),
body: WillPopScope(
onWillPop: () async {
Navigator.of(context).pop({
Fitter.GlutenFree: _glutenFitter,
Fitter.LactoseFree: _lactoseFitter,
Fitter.Vegan: _veganFitter,
Fitter.Vegetarian: _vegeterianFitter,
});
return false;
},
child: Column(
children: [
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('pop')),
FitterItem(
fitterValue: _glutenFitter,
onChange: (bool newValue) {
setState(() {
_glutenFitter = newValue;
});
},
fitterTittle: "Gluten free",
fitterSubTit: "Only include Gluten free meals"),
const SizedBox(
height: 5,
),
FitterItem(
fitterValue: _lactoseFitter,
onChange: (newValue) {
setState(() {
_lactoseFitter = newValue;
});
},
fitterTittle: "Lactose free",
fitterSubTit: "Only include Lactose free meals"),
const SizedBox(
height: 5,
),
FitterItem(
fitterValue: _veganFitter,
onChange: (newValue) {
setState(() {
_veganFitter = newValue;
});
},
fitterTittle: "Vegan free",
fitterSubTit: "Only include Vegan free meals"),
const SizedBox(
height: 5,
),
FitterItem(
fitterValue: _vegeterianFitter,
onChange: (newValue) {
setState(() {
_vegeterianFitter = newValue;
});
},
fitterTittle: "Vegeterian free",
fitterSubTit: "Only include Vegeterian free meals"),
],
),
),
);
}
}
/// end FitterScreen