뽀모도로 앱을 따라 만들면서 flutter의 statefulWidget과 UI를 공부한 것을 기록한다.
강의 참고:
https://nomadcoders.co/flutter-for-beginners/lectures/4154
All Courses – 노마드 코더 Nomad Coders
초급부터 고급까지! 니꼬쌤과 함께 풀스택으로 성장하세요!
nomadcoders.co
순서는 크게 아래와 같다.
1. 파일 생성 및 UI 설계
2. 타이머 시작 & 정지 기능
3. 뽀모도로 개수 카운터 기능
4. 타이머 포맷 설정
5. 타이머 리셋 기능
* 한 뽀모도로를 25분으로 기본 설정하였으나, 디버깅 및 영상 촬영을 위해 5초로 설정하기도 함
1. 파일 생성 및 UI 설계
우선 flutter 프로젝트를 생성하고 main.dart에서 앱의 테마 색을 쉽게 이용하고자 theme을 설정한다. 그리고 화면에 띄울 home screen 파일을 만들고 import하고 화면에 나타낸다.

- main.dart에 ThemeData를 이용해 테마 설정
- Flexible을 이용해 비율대로 화면에 요소 나타내기(타이머: 1, 버튼: 2, 뽀모도로 개수: 1)
- Expanded를 이용해 화면 크기만큼 채운 박스로 요소 나타내기
https://github.com/soaringwave/Flutter-studying/commit/66699bd0116e1f8f51997f49435b85a2f2d5fa20
2. 타이머 시작 & 정지 기능
[시작]
- 1500(초) 정수 값을 가진 totalTimer 정의
- IconButton을 눌렀을 때 1초마다 onTick 함수를 실행하여 totalTime의 값이 1씩 감소
- 이를 setState를 이용해 화면에 표현
int totalTime = 1500;
late Timer timer;
void onTick(Timer timer) {
setState(() {
totalTime = totalTime - 1;
});
}
void onStartPressed() {
timer = Timer.periodic(
const Duration(seconds: 1),
onTick,
);
}
https://github.com/soaringwave/Flutter-studying/commit/6a35caf1ca020f025bea9ea7f6fea97f48c37007
[정지]
- bool 값을 가진 isRunning 변수를 이용하여 타이머의 동작여부 파악
- isRunning 값에 따라 play, pause IconButton을 화면에 보이고 각각 onStartPressed, onPausePressed 함수 실행하기
- pause IconButton을 누르면 진행하던 timer 종료 후 isRunning 상태를 false로 설정
bool isRunning = false;
void onPausePressd() {
timer.cancel();
setState(() {
isRunning = false;
});
}
// ...
IconButton(
iconSize: 120,
color: Theme.of(context).cardColor,
icon: const Icon(Icons.play_circle_filled_sharp),
onPressed: onStartPressed,
icon: Icon(isRunning
? Icons.pause_circle_filled_rounded
: Icons.play_circle_filled_rounded),
onPressed: isRunning ? onPausePressd : onStartPressed,
),
// ...
https://github.com/soaringwave/Flutter-studying/commit/74c945d03c33dd2a06ba59d91dd401991af13af7
3. 뽀모도로 개수 카운터 기능
- totalPomodoros 변수의 값을 0으로 초기화
- 뽀모도로 타이머 시간이 종료되면(0이 되면) 총 뽀모도로 개수를 하나 추가하고 타이머는 25분으로 다시 초기화
int totalPomodoros = 0;
void onTick(Timer timer) {
if (totalTime == 0) {
setState(() {
totalPomodoros = totalPomodoros + 1;
isRunning = false;
totalTime = 1500;
});
timer.cancel();
} else {
setState(() {
totalTime = totalTime - 1;
});
}
}
https://github.com/soaringwave/Flutter-studying/commit/8c9a9dc84fddfa4bef83a7b787a7cba7a1619bc6
4. 타이머 포맷 설정
- 초를 나타내는 정수 값을 인수로 받으면 'nn:nn' 문자열을 반환하는 timeFormat 함수 정의
- Duration을 이용하여 시간을 문자열으로 변환
String timeFormat(int seconds) {
String duration = Duration(seconds: seconds).toString();
return duration.substring(2, 7);
}
// ...
Text(
timeFormat(totalTime),
style: TextStyle(
color: Theme.of(context).cardColor,
fontSize: 90,
fontWeight: FontWeight.w600,
),
),
// ...
+ 문자열 format 참고

https://github.com/soaringwave/Flutter-studying/commit/bd46933a635a0a609e9692d30e22f0a5c01b2852
5. 타이머 리셋 기능
코드 챌린지로 타이머 리셋 기능을 추가했다. play 버튼 아래의 stop 버튼을 클릭하면 타이머가 초기화된다.
void onRestartPressed() {
timer.cancel();
setState(() {
totalTime = twentyFiveMin;
isRunning = false;
});
}
// ...
const SizedBox(
height: 30,
),
IconButton(
iconSize: 60,
color: Theme.of(context).cardColor,
icon: const Icon(Icons.stop_circle_outlined),
onPressed: onRestartPressed,
),
// ...
https://github.com/soaringwave/Flutter-studying/commit/90ab80152f49aa526c156e18fd7363c77aef776b

'프로젝트 > 웹툰 앱 만들기' 카테고리의 다른 글
| [웹툰 앱 만들기] ApiService로 웹툰 정보 받기 (0) | 2023.10.14 |
|---|---|
| [웹툰 앱 만들기] GestureDetector과 detail screen (0) | 2023.10.14 |
| [웹툰 앱 만들기] AppBar 만들기 (0) | 2023.10.13 |
| [웹툰 앱 만들기] Theme, init & dispose (0) | 2023.05.06 |
| [웹툰 앱 만들기] 설치 및 시작 (0) | 2023.04.22 |
댓글