일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- first_app
- StatefulWidget
- first flutter app
- flutter
- Engineer Australia
- 호주 이민
- StatelessWidget
- 기술인증
- reverse proxy
- ABEEK
- 맨붕
- progress
- 앱 기획
- 블러 효과
- Android
- quintus
- 플러터
- OpenGL
- rotate circle
- game engine
- c
- flutter progress dialog
- c++
- 회전판
- BlurDrawable
- 공학인증
- HTML 게임 엔진
- nginx
- ipad
- PowerMockup
- Today
- Total
우동우동우's note
Flutter Progress Dialog에 대한 생각 본문
익숙함에서 찾은 방법
나는 Android App 개발을 하다가 Flutter를 이번에 처음 접하게 되었다. Android 앱에서 Dialog를 나타내는 방식은 Dialog 객체를 생성 후 show 함수를 불러 보여주고 지울 때 dismiss 함수를 불러서 삭제하는 방식이다. 이러한 방식은 객체 지향 언어에서 자연스럽게 사용하는 방식이며 특정 이벤트때 해당 함수를 call 하는 방식으로 매우 간단하다. 그리고 dialog는 Activity 속해 있는 것임으로 제어가 용이하다.
그때의 익숙함 때문에 나도 Pregress Dialog를 유사한 형태로 개발된 open 소스를 찾았다. flutter pregress dialog를 검색창에 치면 가장 먼저 나오는 것이다. progress_dialog 라이브러리일 것이다. 이 라이브러리를 사용하는 방식은 Android에서 Dialog를 제어하는 방식과 매우 유사하다. Dialog 객체를 생성하고, show 함수로 나타내고 dismiss 함수로 닫는다.
그런데 이 progress dialog에서 문제점을 하나 발경하였다. 그 문제는 동일 Thread에서 켜고 끄는 관리가 어렵다는 것이다. flutter의 내부의 구조를 더 자세하게 파악해야 하나 일단 라이브러리에서 progress_dialog.dart 소스에서 show 함수와 dismiss 함수를 살펴보면 이해가 될 것이다.
show 함수를 보면 showDialog 함수를 사용하여 하나의 Dialog객체를 만들어서 Dialog를 나타내고 있다. 그리고 Dialog 객체를 저장하고 있지 않으며 showDialog 함수는 새로운 화면을 기존 화면 위에 Stack으로 쌓아 두도록 되어있다.
다음으로 dissmiss 함수의 코드를 발췌하면 다음과 같다.
void dismiss() {
if (_isShowing) {
try {
_isShowing = false;
if (Navigator.of(_dismissingContext).canPop()) {
Navigator.of(_dismissingContext).pop();
if (_showLogs) debugPrint('ProgressDialog dismissed');
} else {
if (_showLogs) debugPrint('Cant pop ProgressDialog');
}
} catch (_) {}
} else {
if (_showLogs) debugPrint('ProgressDialog already dismissed');
}
}
여기서 잘 주목할 점은.. _isShowing 필드인데 이 파일의 최상단을 보면 static 변수로 선언된 bool 값이다. 즉, progressDialog는 앱 전체에 1개의 개체만 만들어야 하고, 이 개체를 컨트롤 하기 위해서 어떤 Widget이 이 개체를 소유하는 것이 불가능하다는 것이다.
또한 Navigator.of(context).pop() 함수를 보면 지금 떠있는 객체가 누구임을 확인하지 않고 pop을 한다. 즉 _isShowing 상태이면 pop 한다는 것이다. 전역변수로 나와 있는 값을 믿는 것이다. 지금 업애는 화면이 누구인지를 확인하지 않고....
show함수가 불려지고 dialog가 나타나기 전에 이 dismiss 함수가 불려지면 Navigator.of(content).canPop() 함수에서 false가 나와서 아무런 동작은 하지 않고 _isShowing 값만 false로 바꿔버린다. 이렇게 되면 화면은 지우지 않고 dialog를 지워진 상태로 인식해버리는 문제가 발생한다....
때문에 해당 라이브러리를 변형하여 객체화 하여 만들어 보려고 고민하였으나 showDialog 함수의 행위와 Navigator.pop으로 제어해야하는 dialog를 깔끔하게 하나의 객체로 제어하기란 너무 어려운 일이었다.
State에 따라 Widget 제어하기(예제)
때문에 나는 Flutter에서 View를 표현하는 방식을 생각해 보았다. Flutter에서는 StatelessWidget과 StatefulWidget 두가지의 widget이 있다. 이중에서 StatefulWidget은 state에 따라 매번 다른 Widget에 변화를 줄 수 있다. 그렇다면 통신 중일 때는 다른 State로 인식하고 다른 progress를 dialog로 만드는 것이 아니라 하나의 제어가능한 wiget으로 dialog 처럼 나타내는 것이 더 효율적이라고 생각한다.
이러한 방식으로 progress를 나타내는 예제를 하나 만들었다. floatingActionButton을 누르면 progress가 2초간 나오고 사라지도록 한 예제이다. github에 소스를 공개해 놓았으니 소스가 필요하다면 참고하길 바란다.
예제에서 lib/main.dart 파일을 보면 _isDialogVisible이라는 변수가 State 클래스 내부에 있고, 이 값에 따라 Visibility Widget 내에 visible 값이 변경되도록 하였다. 이렇게 되면 _ProgressExampleState 클래스 안에서 State의 제어만으로 Progress Dialog의 생성을 할 수 있다는 것이다. 또한 이 방법은 동일 Thread 상에서 작동 시켜도 아무런 문제가 일어나지 않는다.
class _ProgressExampleState extends State<ProgressExample> {
bool _isDialogVisible = false; // 다이얼로그 visible
void _showDialog() {
setState(() {
_isDialogVisible = true;
});
Future.delayed(Duration(seconds: 2), () { // 2초 뒤에 false로 변경
setState(() {
_isDialogVisible = false;
});
});
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Content',
),
],
),
),
floatingActionButton: FloatingActionButton( // 버튼을 누르면 프로그래스 다이얼로그 나타냄
onPressed: _showDialog,
tooltip: 'Send',
child: Icon(Icons.send),
),
),
Visibility(
visible: _isDialogVisible,
child: Container(
color: Colors.black26,
alignment: Alignment.center,
child: Padding(
padding: EdgeInsets.all(10.0),
child: CircularProgressIndicator(),
),
))
],
);
}
}
Flutter 에서 어떠한 변화의 상태를 나타내기위해서 ProgressDialog를 나타내야 한다면 showDialog 함수를 이용하는 것 보다는 State를 변화시켜 ProgressDialog를 나타내는 것이 더 깔끔하고, 안전한 개발이 가능하다.
'Flutter' 카테고리의 다른 글
[Dart] 변수형에서 getter / setter로 변경 (0) | 2020.06.05 |
---|---|
[Flutter] Progress Dialog 라이브러리 (2) | 2020.05.15 |
[Flutter] 다이얼로그 그림자 제거 (3) | 2020.05.08 |
[Flutter] TextField maxLine 없이 Multi Line 설정 (0) | 2020.03.17 |