为什么父小部件 setState 在 flutter 中禁用子小部件 setState?
Why parent widget setState disables child widget setState in flutter?
我尝试为我的 flutter 应用程序创建一个日期选择器。起初我可以选择我想要的日子,所选日期的颜色会改变。问题是当我在下拉按钮中更改月份或年份时,我无法更改选定的日期。实际上一切正常,选择的日期将返回,但它的颜色不会改变。我是新手
这是我的代码。
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_datepicker/calander_body/day_box.dart';
class CalanderDays extends StatefulWidget {
final onSelectDays;
CalanderDays({required this.onSelectDays});
@override
State<StatefulWidget> createState() => CalanderDaysState();
}
class CalanderDaysState extends State<CalanderDays> {
int previousIndex = 0;
int? monthDrop = 0;
int? yearDropDowninit = 1940;
List monthNames = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
String? year, month, day;
String? fullDate;
@override
Widget build(BuildContext context) {
List<DropdownMenuItem<int>> monthDropDown = List.generate(12, (index) {
return DropdownMenuItem(
child: Text(monthNames[index]),
value: index,
);
});
List<DropdownMenuItem<int>> yearItems =
List.generate(DateTime.now().year - 1950, (index) {
return DropdownMenuItem(
child: Text('${1950 + index}'),
value: 1950 + index,
);
});
List<DayBox>? days = List.generate(30, (index) {
return DayBox(
day: index,
);
});
return Directionality(
textDirection: TextDirection.rtl,
child: Flexible(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: Row(
textDirection: TextDirection.rtl,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
DropdownButton<int>(
iconEnabledColor: Colors.black,
value: monthDrop,
items: monthDropDown,
onChanged: (itemValue) {
month = itemValue.toString();
setState(() {
monthDrop = itemValue;
});
}),
DropdownButton<int>(
value: yearDropDowninit,
items: yearItems,
onChanged: (value) {
year = value.toString();
setState(() {
yearDropDowninit = value;
});
})
],
)),
Flexible(
flex: 5,
child: GridView.builder(
itemCount: 31,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 7),
itemBuilder: (context, i) {
return InkWell(
onTap: () {
int selectedDay = i + 1;
day = selectedDay.toString().length == 1
? day = '0$selectedDay'
: selectedDay.toString();
print(day);
if (i == previousIndex) {
print('previous');
} else if (i != previousIndex) {
days[i].activate();
days[previousIndex].deactivate();
previousIndex = i;
if (previousIndex == -1) {
print('-1');
return;
}
}
},
child: days[i],
);
}))
],
)));
}
}
dayBox 小部件:
import 'package:flutter/material.dart';
class DayBox extends StatefulWidget {
final day;
VoidCallback activate = () {};
VoidCallback deactivate = () {};
DayBox({Key? key, required this.day}) : super(key: key);
@override
State<StatefulWidget> createState() => DayBoxState();
}
class DayBoxState extends State<DayBox> {
Color boxColor = Colors.transparent;
Color textColor = Colors.black;
@override
void initState() {
super.initState();
widget.activate = active;
widget.deactivate = deactivate;
}
active() {
Future.delayed(Duration.zero, () {
setState(() {
boxColor = Colors.red;
textColor = Colors.white;
});
});
}
deactivate() {
Future.delayed(Duration.zero, () {
setState(() {
boxColor = Colors.transparent;
textColor = Colors.black;
});
});
}
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
width: 30,
height: 30,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: boxColor,
),
child: Text(
'${widget.day + 1}',
style: TextStyle(
fontSize: 18,
color: textColor,
fontWeight: FontWeight.normal,
decoration: TextDecoration.none),
),
);
}
}
真不知道该怎么办
Solution ^^ : Make DayBox extend a stateless Widget
class CalanderDays extends StatefulWidget {
// final onSelectDays;
CalanderDays();
@override
State<StatefulWidget> createState() => CalanderDaysState();
}
class CalanderDaysState extends State<CalanderDays> {
int previousIndex = 0;
int? monthDrop = 0;
int yearDropDowninit = 1940;
int _day = 1;
List monthNames = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
String? year, month, day;
String? fullDate;
@override
Widget build(BuildContext context) {
List<DropdownMenuItem<int>> monthDropDown = List.generate(12, (index) {
return DropdownMenuItem(
child: Text(monthNames[index]),
value: index,
);
});
List<DropdownMenuItem<int>> yearItems =[];
for(int i= yearDropDowninit;i<=DateTime.now().year;i++){
yearItems.add(DropdownMenuItem(
child: Text('${i}'),
value: i,
));
}
List.generate(DateTime.now().year - yearDropDowninit, (index) {
return DropdownMenuItem(
child: Text('${1950 + index}'),
value: 1950 + index,
);
});
return Directionality(
textDirection: TextDirection.rtl,
child: Flexible(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: Row(
textDirection: TextDirection.rtl,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
DropdownButton<int>(
iconEnabledColor: Colors.black,
value: monthDrop,
items: monthDropDown,
onChanged: (itemValue) {
month = itemValue.toString();
setState(() {
monthDrop = itemValue;
});
}),
DropdownButton<int>(
value: yearDropDowninit,
items: yearItems,
onChanged: (value) {
year = value.toString();
setState(() {
yearDropDowninit = value!;
});
})
],
)),
Flexible(
flex: 5,
child: GridView.builder(
itemCount: days.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 7),
itemBuilder: (context, index) {
return InkWell(
onTap: () {
setState(() {
_day =index;
});
},
child: BoxDay(
day: index, activated: _day == index ,
) ,
);
}))
],
)));
}
}
class BoxDay extends StatelessWidget {
final day;
final bool activated;
const BoxDay({Key? key, required this.activate, this.day}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
width: 30,
height: 30,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: activated ? Colors.red : Colors.transparent,
),
child: Text(
'${day + 1}',
style: TextStyle(
fontSize: 18,
color: activated ? Colors.white : Colors.black,
fontWeight: FontWeight.normal,
decoration: TextDecoration.none),
),
);
}
}
出现错误,
List<DropdownMenuItem<int>> yearItems =
List.generate(DateTime.now().year - 1950, (index) {
return DropdownMenuItem(
child: Text('${1950 + index}'),
value: 1950 + index,
);
});
to
List<DropdownMenuItem<int>> yearItems =[];
for(int i= yearDropDowninit;i<=DateTime.now().year;i++){
yearItems.add(DropdownMenuItem(
child: Text('${i}'),
value: i,
));
}
我尝试为我的 flutter 应用程序创建一个日期选择器。起初我可以选择我想要的日子,所选日期的颜色会改变。问题是当我在下拉按钮中更改月份或年份时,我无法更改选定的日期。实际上一切正常,选择的日期将返回,但它的颜色不会改变。我是新手 这是我的代码。
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_datepicker/calander_body/day_box.dart';
class CalanderDays extends StatefulWidget {
final onSelectDays;
CalanderDays({required this.onSelectDays});
@override
State<StatefulWidget> createState() => CalanderDaysState();
}
class CalanderDaysState extends State<CalanderDays> {
int previousIndex = 0;
int? monthDrop = 0;
int? yearDropDowninit = 1940;
List monthNames = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
String? year, month, day;
String? fullDate;
@override
Widget build(BuildContext context) {
List<DropdownMenuItem<int>> monthDropDown = List.generate(12, (index) {
return DropdownMenuItem(
child: Text(monthNames[index]),
value: index,
);
});
List<DropdownMenuItem<int>> yearItems =
List.generate(DateTime.now().year - 1950, (index) {
return DropdownMenuItem(
child: Text('${1950 + index}'),
value: 1950 + index,
);
});
List<DayBox>? days = List.generate(30, (index) {
return DayBox(
day: index,
);
});
return Directionality(
textDirection: TextDirection.rtl,
child: Flexible(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: Row(
textDirection: TextDirection.rtl,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
DropdownButton<int>(
iconEnabledColor: Colors.black,
value: monthDrop,
items: monthDropDown,
onChanged: (itemValue) {
month = itemValue.toString();
setState(() {
monthDrop = itemValue;
});
}),
DropdownButton<int>(
value: yearDropDowninit,
items: yearItems,
onChanged: (value) {
year = value.toString();
setState(() {
yearDropDowninit = value;
});
})
],
)),
Flexible(
flex: 5,
child: GridView.builder(
itemCount: 31,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 7),
itemBuilder: (context, i) {
return InkWell(
onTap: () {
int selectedDay = i + 1;
day = selectedDay.toString().length == 1
? day = '0$selectedDay'
: selectedDay.toString();
print(day);
if (i == previousIndex) {
print('previous');
} else if (i != previousIndex) {
days[i].activate();
days[previousIndex].deactivate();
previousIndex = i;
if (previousIndex == -1) {
print('-1');
return;
}
}
},
child: days[i],
);
}))
],
)));
}
}
dayBox 小部件:
import 'package:flutter/material.dart';
class DayBox extends StatefulWidget {
final day;
VoidCallback activate = () {};
VoidCallback deactivate = () {};
DayBox({Key? key, required this.day}) : super(key: key);
@override
State<StatefulWidget> createState() => DayBoxState();
}
class DayBoxState extends State<DayBox> {
Color boxColor = Colors.transparent;
Color textColor = Colors.black;
@override
void initState() {
super.initState();
widget.activate = active;
widget.deactivate = deactivate;
}
active() {
Future.delayed(Duration.zero, () {
setState(() {
boxColor = Colors.red;
textColor = Colors.white;
});
});
}
deactivate() {
Future.delayed(Duration.zero, () {
setState(() {
boxColor = Colors.transparent;
textColor = Colors.black;
});
});
}
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
width: 30,
height: 30,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: boxColor,
),
child: Text(
'${widget.day + 1}',
style: TextStyle(
fontSize: 18,
color: textColor,
fontWeight: FontWeight.normal,
decoration: TextDecoration.none),
),
);
}
}
真不知道该怎么办
Solution ^^ : Make DayBox extend a stateless Widget
class CalanderDays extends StatefulWidget {
// final onSelectDays;
CalanderDays();
@override
State<StatefulWidget> createState() => CalanderDaysState();
}
class CalanderDaysState extends State<CalanderDays> {
int previousIndex = 0;
int? monthDrop = 0;
int yearDropDowninit = 1940;
int _day = 1;
List monthNames = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
String? year, month, day;
String? fullDate;
@override
Widget build(BuildContext context) {
List<DropdownMenuItem<int>> monthDropDown = List.generate(12, (index) {
return DropdownMenuItem(
child: Text(monthNames[index]),
value: index,
);
});
List<DropdownMenuItem<int>> yearItems =[];
for(int i= yearDropDowninit;i<=DateTime.now().year;i++){
yearItems.add(DropdownMenuItem(
child: Text('${i}'),
value: i,
));
}
List.generate(DateTime.now().year - yearDropDowninit, (index) {
return DropdownMenuItem(
child: Text('${1950 + index}'),
value: 1950 + index,
);
});
return Directionality(
textDirection: TextDirection.rtl,
child: Flexible(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: Row(
textDirection: TextDirection.rtl,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
DropdownButton<int>(
iconEnabledColor: Colors.black,
value: monthDrop,
items: monthDropDown,
onChanged: (itemValue) {
month = itemValue.toString();
setState(() {
monthDrop = itemValue;
});
}),
DropdownButton<int>(
value: yearDropDowninit,
items: yearItems,
onChanged: (value) {
year = value.toString();
setState(() {
yearDropDowninit = value!;
});
})
],
)),
Flexible(
flex: 5,
child: GridView.builder(
itemCount: days.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 7),
itemBuilder: (context, index) {
return InkWell(
onTap: () {
setState(() {
_day =index;
});
},
child: BoxDay(
day: index, activated: _day == index ,
) ,
);
}))
],
)));
}
}
class BoxDay extends StatelessWidget {
final day;
final bool activated;
const BoxDay({Key? key, required this.activate, this.day}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
width: 30,
height: 30,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: activated ? Colors.red : Colors.transparent,
),
child: Text(
'${day + 1}',
style: TextStyle(
fontSize: 18,
color: activated ? Colors.white : Colors.black,
fontWeight: FontWeight.normal,
decoration: TextDecoration.none),
),
);
}
}
出现错误,
List<DropdownMenuItem<int>> yearItems =
List.generate(DateTime.now().year - 1950, (index) {
return DropdownMenuItem(
child: Text('${1950 + index}'),
value: 1950 + index,
);
});
to
List<DropdownMenuItem<int>> yearItems =[];
for(int i= yearDropDowninit;i<=DateTime.now().year;i++){
yearItems.add(DropdownMenuItem(
child: Text('${i}'),
value: i,
));
}