Flutter

[Flutter] 타이머(Timer)

에릭 Kim 2022. 6. 22. 19:39
반응형

Key Points

  • Timer 클래스

: 비동기 방식(요청을 보냈을 때 응답과 상관없이 다음 동작 수행가능). Timer 클래스는 앱을 종료할 때 동작을 취소해줘야 하기 때문에 dispose() 메소드가 꼭 필요합니다.. 아니면 백그라운드에서 계속해서 돌아갑니다. 

  • setState()

: state에서 무언가 변화가 일어났음을 알려주는 함수. setState()를 통해서 UI가 변경될 수 있게 다시 build됩니다. 또한 StatefulWidget에서 상태 변경을 나타내기 위해 가장 많이 사용합니다. 

  • Map()

: Map 함수는 iterable한 값을 가공하여, iterable로 반환하는 함수인데, forEach 함수는 단순 루프인것에 반해 Map함수는 반환 값이 존재합니다.

 

import 'package:flutter/material.dart';
import 'dart:async';

class Stopwatch extends StatefulWidget {
  const Stopwatch({Key? key}) : super(key: key);

  @override
  _StopwatchState createState() => _StopwatchState();
}

class _StopwatchState extends State<Stopwatch> {
  late Timer _timer; // 타이머 선언

  var _time = 0; // 변수 선언
  var _isRunning = false; // 시작 상태 확인

  List<String> _lapTimes = []; // laptime을 기록할 리스트 생성

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('StopWatch'),
        backgroundColor: Colors.lightGreen,
      ),
      body: _buildBody(),
      bottomNavigationBar: BottomAppBar(
        child: Container(
          height: 50,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => setState(() {
          _clickButton();
        }),
        child: _isRunning ? Icon(Icons.pause) : Icon(Icons.play_arrow),
        backgroundColor: Colors.lightGreen, // 시작 상태를 확인하면 버튼 변경
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    );
  }

  Widget _buildBody() {
    // 초를 계산하는 위젯
    var sec = _time ~/ 100; // 초
    var hundredth = '${_time % 100}'.padLeft(2, '0'); // 1/100초

    return Container(
        child: Padding(
            padding: const EdgeInsets.only(top: 30),
            child: Stack(
              // Stack 위젯을 사용하여 여러 위젯을 겹치게 사용
              children: <Widget>[
                Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      crossAxisAlignment: CrossAxisAlignment.end,
                      children: [
                        Text(
                          '$sec',
                          style: TextStyle(fontSize: 50),
                        ),
                        Text('$hundredth'),
                      ],
                    ),
                    SizedBox(
                      height: 30,
                    ),
                    Container(
                        width: 30,
                        height: 200,
                        child: ListView(
                          children:
                              _lapTimes.map((time) => Text(time)).toList(),
                          // 리스트의 값을 text로 바꾸고, 다시 List로 변환
                        ))
                  ],
                ),
                Positioned(
                    left: 10,
                    bottom: 10,
                    child: FloatingActionButton(
                      backgroundColor: Colors.deepOrange,
                      onPressed: _reset,
                      child: Icon(Icons.rotate_left),
                    )),
                Positioned(
                    right: 10,
                    bottom: 10,
                    child: RaisedButton(
                      onPressed: () {
                        setState(() {
                          _recordLapTime('$sec.$hundredth');
                        });
                      },
                      child: Text('Lab'),
                    ))
              ],
            )));
  }

  void _clickButton() {
    // 시작 버튼
    _isRunning = !_isRunning;
    if (_isRunning) {
      // _isRunning의 값에 따라서 _start(),_pause() 실행
      _start();
    } else {
      _pause();
    }
  }

  void _start() {
    // 시작
    _timer = Timer.periodic(Duration(milliseconds: 10), (timer) {
      // Duration()을 사용하여, 1/100초에 한번씩 1 증가
      setState(() {
        _time++;
      });
    });
  }

  void _pause() {
    // 멈춤
    _timer?.cancel();
  }

  void _reset() {
    // 초기화
    setState(() {
      _isRunning = false;
      _timer?.cancel();
      _lapTimes.clear();
      _time = 0;
    });
  }

  @override
  void dispose() {
    // Controller 객체가 제거될 때 변수에 할당된 메모리를 해제하기 위해 dispose 메소드 사용
    _timer?.cancel();
    super.dispose();
  }

  void _recordLapTime(String time) {
    // 랩타임
    _lapTimes.insert(0, '$time');
  }
}

 

 

 

반응형