
flutter version 2.5.2 기준으로 작성됨
dialog를 호출한 위젯의 상태도 바꾸고 싶은 경우와 아닌 경우를 나눠서 설명dialog 내부의 상태만 변경하고 싶을 때
The widget returned by the builder does not share a context with the location that showDialog is originally called from. Use a StatefulBuilder or a custom StatefulWidget if the dialog needs to update dynamically.
showDialog 문서에서는 호출한 곳의 context를 공유하지 않으니, Dialog를 동적으로 변경하고 싶으면 StatefulBuilder나 StatefulWidget으로 사용하라고 적혀있음
StatefulBuilder 사용Dialog에서 상태 변경을 원하는 위젯을 StatefulBuilder로 감싸서 사용Future<dynamic> showStatefulBuilderDialog(BuildContext context) async {
await showDialog<void>(
context: context,
builder: (_) {
int? selectedRadio = 0;
return AlertDialog(
content: StatefulBuilder(
builder: (__, StateSetter setState) {
return Column(
mainAxisSize: MainAxisSize.min,
children: List<Widget>.generate(3, (int index) {
return Radio<int>(
value: index,
groupValue: selectedRadio,
onChanged: (int? value) {
setState(() => selectedRadio = value);
},
);
}),
);
},
),
);
},
);
}
StatefulWidget 사용Dialog를 StatefulWidget으로 커스텀해서 사용함// dialog를 사용하는 곳
Future<dynamic> showStatefulWidgetDialog(BuildContext context) async {
await showDialog<void>(
context: context,
builder: (_) {
return MyStatefulDialog();
},
);
}
// StatefulWidget으로 dialog 작성
class MyStatefulDialog extends StatefulWidget {
State<MyStatefulDialog> createState() => _MyStatefulDialogState();
}
class _MyStatefulDialogState extends State<MyStatefulDialog> {
int? selectedRadio = 0;
Widget build(BuildContext context) {
return AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: List<Widget>.generate(3, (int index) {
return Radio<int>(
value: index,
groupValue: selectedRadio,
onChanged: (int? value) {
setState(() => selectedRadio = value);
},
);
}),
),
);
}
}
Dialog를 호출한 위젯에도 Dialog의 변경 값을 바로바로 표시하고 싶을 때Dialog를StatefulWidget으로 분리하여 구현한 경우는 잘 작동하므로 제외하겠음
StatefulBuilder 사용StatefulWidget에서 StatefulBuilder를 사용한 경우 이미 setState()가 존재하므로 StatefulBuilder의 StateSetter의 메서드명을setState로 선언하면 이름이 중복되는 문제가 발생한다Builder 안의 StateSetter setState가 호출되므로 원하던 바깥 위젯의 상태는 변경되지 않는다 (context share 안함)
설명을 위해 코드를 짧게 한 스샷이며,
setState의 주인은 각각 색깔로 매칭함
StateSetter의 setState를 다른 이름으로 선언해주면 잘 동작한다Future<dynamic> showStatefulDialog() async {
await showDialog<void>(
context: context,
builder: (_) {
int? selectedRadio = 0;
return AlertDialog(
content: StatefulBuilder(
builder: (__, StateSetter setDialogState) { // 변수명 변경
return Column(
mainAxisSize: MainAxisSize.min,
children: List<Widget>.generate(3, (int index) {
return Radio<int>(
value: index,
groupValue: selectedRadio,
onChanged: (int? value) {
setDialogState(() => selectedRadio = value);
setState(() => text = 'MyStatefulWidget $value');
},
);
}),
);
},
),
);
},
);
}