Timer를 활용하여 타이머 만들기(Flutter)

2024. 8. 15. 04:17Flutter

 

오늘은 플러터에서 Timer를 만들어보았다

처음에는 어떻게 만들어야 할 지 잘 모르겠어서 블로그를 찾아봤는데

 

Timer만 있거나 또는 CircularProgressIndicator만 활용해서 구현한 타이머들 밖에 볼 수 없었다

하지만 나는 그 두가지를 다 이용하여 구현을 해야했기 때문에

한 번 구현을 해보았다!

 

 

우선 가장 먼저 

내가 몇 분을 지정할 것인지와 타이머 객체등을 만들어줬다

 

 static const maxSecond = 1500; //25분
  int remainingSecond = maxSecond;  // 남은 시간
  Timer? _timer;
  bool isRunning = false;

 

옆에 주석을 보면 이해가 편할 거 같다

 

 

다음으로는 버튼을 통해서 타이머를 시작해줄 것이기 때문에

함수를 하나 만들어줬다

 

void startTimer(){
    _timer = Timer.periodic(Duration(seconds: 1), (timer){
      setState(() {
        if (remainingSecond > 0) {
          remainingSecond--;  //남은 시간을 1초씩 줄인다
        }  
        else{
          _timer?.cancel();  //시간이 0이되면 타이머 중지
        }
      });
    });
  }

 

위의 코드처럼 남은 시간(remainingSecond)이 0보다 클 경우

남은 시간을 1초씩 줄이고

만약 그렇지 않다면 타이머를 중지 시킨다

 

 

이후 우리 프로젝트에서는 타이머를 중지 시켰다가 다시 실행을 시켜야 하기 때문에

함수를 하나 더 만들어줬다

void toggleTimer(){
    if (isRunning) {
      //타이머를 일시 정지
      _timer?.cancel();
    }  else{
      //재시작
      startTimer();
    }
    setState(() {
      isRunning = !isRunning;
    });
  }

 

위의 코드처럼 타이머가 isRunning 즉 실행 중일 때 버튼을 누르면 타이머를 중지시키고

isRunning이 아닐 때에는 재시작을 시켜주는 함수이다

 

 

 

다음으로는 우리가 시간을 1500초로 지정했으니 이걸 시간으로 바꿔주는 함수를 만들어줬다

String formatTime(int seconds){
    int minutes = seconds ~/ 60;
    int sec = seconds % 60;
    return '${minutes.toString().padLeft(2, '0')}:${sec.toString().padLeft(2, '0')}';
  }

 

위의 코드처럼 seconds를 매개변수로 받고

받아온 seconds를 통해서 우리가 아는 시간으로 바꿔준다

 

 

이제는 CircularProgressIndicator를 사용해보자

CircularProgressIndicator(
                          backgroundColor: Colors.cyanAccent,
                          strokeWidth: 20,
                          value: remainingSecond / maxSecond , //점점 줄어들게끔 구현
                          valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
                        ),

 

위의 코드를 보면 background 색을 지정해줬고

value에 시간이 점점 줄어들게끔 구현을 해준다

또한 valueColor를 통해서 시간이 줄어드는 것을 직관적으로 확인할 수 있게 해준다

 

 

 

마지막으로 타이머를 중지, 실행 시킬 수 있는 버튼을 봐보도록 하자

IconButton(
                                  onPressed: toggleTimer,
                                  iconSize: 60,
                                  icon: Icon(
                                    isRunning
                                        ? Icons.pause
                                        : Icons.play_arrow,
                                    color: Colors.white,
                                  ),
                              )

 

이렇게 구현을 해줬다

위에서 만들었던 toggleTimer를 지정해주고

icon은 상태에 따라서 바뀌어야 하기 때문에 

저렇게 지정을 해줬다

 

 

 

 

이건 전체 코드이다!

class TimerScreen extends StatefulWidget {
  const TimerScreen({super.key});

  @override
  State<TimerScreen> createState() => _TimerScreenState();
}

class _TimerScreenState extends State<TimerScreen> with TickerProviderStateMixin {
  
  static const maxSecond = 1500; //25분
  int remainingSecond = maxSecond;  // 남은 시간
  Timer? _timer;
  bool isRunning = false;

  @override
  void dispose() {
    // TODO: implement dispose
    _timer?.cancel();
    super.dispose();
  }
  
  void startTimer(){
    _timer = Timer.periodic(Duration(seconds: 1), (timer){
      setState(() {
        if (remainingSecond > 0) {
          remainingSecond--;  //남은 시간을 1초씩 줄인다
        }  
        else{
          _timer?.cancel();  //시간이 0이되면 타이머 중지
        }
      });
    });
  }
  
  void toggleTimer(){
    if (isRunning) {
      //타이머를 일시 정지
      _timer?.cancel();
    }  else{
      //재시작
      startTimer();
    }
    setState(() {
      isRunning = !isRunning;
    });
  }
  
  //시간 변환
  String formatTime(int seconds){
    int minutes = seconds ~/ 60;
    int sec = seconds % 60;
    return '${minutes.toString().padLeft(2, '0')}:${sec.toString().padLeft(2, '0')}';
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black12,
      body: SafeArea(
        child: Container(
          padding: EdgeInsets.all(20),
          margin: EdgeInsets.fromLTRB(0, 30, 0, 0),
          child: Align(
            alignment: Alignment.center,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Text("경영시험 공부하기에", style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 18),),
                Text("일단 딱 25분 만 집중해보아요!",  style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 18)),
                SizedBox(height: 50,),
                Center(
                  child: SizedBox(
                    width: 300,
                    height: 300,
                    child: Stack(
                      fit: StackFit.expand,
                      children: [
                        CircularProgressIndicator(
                          backgroundColor: Colors.cyanAccent,
                          strokeWidth: 20,
                          value: remainingSecond / maxSecond , //점점 줄어들게끔 구현
                          valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
                        ),
                        Center(
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              Text("남은 시간", style: TextStyle(fontSize: 20),),
                              Text(
                                formatTime(remainingSecond),
                                style: TextStyle(fontSize: 50, color: Colors.lightGreenAccent),
                              ),
                              IconButton(
                                  onPressed: toggleTimer,
                                  iconSize: 60,
                                  icon: Icon(
                                    isRunning
                                        ? Icons.pause
                                        : Icons.play_arrow,
                                    color: Colors.white,
                                  ),
                              )
                            ],
                          )
                        )
                      ],
                    ),
                  ),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

 

 

 

화면 기록 2024-08-15 오전 4.20.31.mov
1.39MB