-
[ Flutter ] BottomModal CallBack FunctionApplication/Flutter 2024. 12. 22. 17:38반응형
bottomModal을 사용하면서 완료를 눌렀을때 뿐만 아닌 모달이 닫혔을때도 값을 전달하고자 한다.
기존에는 Navigator.pop(context,value) 방식으로 모달이 닫힐때 값 전달을 처리했지만
이는 특정 버튼을 눌렀을때 혹은 특정 동작을 했을때만 처리가 가능하고 단순히 뒤로가기 혹은 모달 외부 클릭시 값 전달 방법이 없어
callBack 함수를 이용.
PopScope를 활용해보고자 했지만 모달을 닫기전에만 컨트롤을 할 수 있었을 뿐 모달이 닫히면서 값 전달이 안되었다.
텍스트 수정을 위해 연필 아이콘을 누르면 단순 input창이 나오는 bottomModal을 구현
이후 모달이 닫을때 자동으로 수정되게 처리
CallBack Function
CallBack 함수 선언
class BottomModalInput extends StatefulWidget { final String? title; final String? money; final Function(String) onValueChanged; const BottomModalInput( {this.title, this.money, required this.onValueChanged, super.key}); @override State<BottomModalInput> createState() => _BottomModalInputState(); }
이후 onSubmitted속성을 추가하여 사용자가 입력 후 키보드에서 완료를 누르면 팝업이 닫히면서 callback 함수에 값을 전달하도록 설정
modal에서 완료 버튼이 아닌 뒤로가기 혹은 modal외부를 눌렀을때도 현재 입력되어있는 값을 전달해주기 위해서 dispose에다가 callback함수를 호출했다.
이때 dispose에서 navigator.pop을 사용하면 dispose는 이미 navigator.pop이 실행되고나서 실행되므로 두번 실행이 되는것으로 인식되며 에러가 발생하게 된다.
이를 방지하기 위해 만약 사용자가 입력 후 완료를 하면 callback함수를 호출하고 navigator.pop으로 닫아주며,
이후 dispose가 실행이 되는데 완료를 눌렀을때는 _isSubmiited로 flag를 설정하여 완료를 눌렀을 경우에는 callback함수가 호출되지 않도록 하며, 뒤로가기 혹은 화면 외부를 눌렀을때만 callback함수가 실행되도록 한다.
@override void dispose() { if (!_isSubmitted) { widget.onValueChanged(_textController.text); } _textController.dispose(); _focusNode.dispose(); super.dispose(); }
bottomModal을 사용하면서 해당 modal의 높이가 적으면 keyboardAvoider를 사용해도 modal이 재대로 안나오는 경우가 발생
이를 해결하기 위해서 keyboard의 높이를 가져오고 modal의 높이를 추가해준다.
그러면 키보드의 높이 + modal높이로 인하여 keyboardAvoider속성을 사용하지 않아도 자연스럽게 키보드의 위에 modal이 나오게 된다.
@override Widget build(BuildContext context) { final keyboardHeight = MediaQuery.of(context).viewInsets.bottom; return Container( width: screenSize(context).width, height: keyboardHeight + 64, decoration: BoxDecoration( color: boxColor, ), child: Padding( padding: EdgeInsets.all(0.0), child: TextField( controller: _textController, focusNode: _focusNode, decoration: const InputDecoration( border: OutlineInputBorder(borderSide: BorderSide.none)), style: TextStyle(color: textColor), keyboardType: keyboardType, onSubmitted: (value) { widget.onValueChanged(value); _isSubmitted = true; Navigator.pop(context); }, ), ), ); }
Processing
callback함수가 호출된 시점에서 값 변경처리 함수를 실행
onTap: () { showModalBottomSheet( context: context, builder: (context) => BottomModalInput( title: incomeMsg, onValueChanged: (value) { _updateIncomeMsg(value); }, ), ); },
여기서 단순히 setState만을 사용해서 값 변경을 시도해보았지만
다음과 같은 오류가 발생
======== Exception caught by widgets library ======================================================= The following assertion was thrown while finalizing the widget tree: setState() or markNeedsBuild() called when widget tree was locked.
이 에러의 원인을 재대로 파악은 못하였지만,
위젯 트리가 초기화하고 다시 렌더링 하는 과정에서 충돌이 일어날 수 있다고 하였고,
변수를 초기화 과정에서 provider로 가져온 값으로 초기화하는 것이 이유 일 수도 있다고 판단
기존의 변수 초기화시에는 build에서 직접 provider를 불러서 초기화를 했는데 이 오류가 발생하면서 initState를 사용하면서
해당 위젯이 생성될때 초기에서 provider를 호출하고 초기값을 세팅해주는 방식으로 변경
그로 인하여 setState의 실행 시점을 늦춰주기위해서
delay 방식과 addPostFrameCallback방식 중 callback방식으로 사용
void _updateIncomeMsg(String msg) { WidgetsBinding.instance.addPostFrameCallback((_) { setState(() { incomeMsg = msg; }); }); }
이러면 값이 정상적으로 변경되는 것을 확인할 수 있다.
728x90반응형'Application > Flutter' 카테고리의 다른 글
[ Flutter ] Text Widget 테두리 색 내부 색 변경 (0) 2024.12.28 [ Flutter ] Progress Bar (2) 2024.12.25 [ Flutter ] App Icon Generate (0) 2024.12.22 [ Flutter ] ListView Auto Scroll Controller (0) 2024.12.15 [ Flutter ] Text Rich (0) 2024.12.14