[Flutter] 시계 기능 작성
이번에는 시계 기능이 동작하도록 변경해 볼 것입니다.
먼저 기존 코드에서 Clock
클래스를 지우고 StatefulWidget
으로 새로 작성하여 줍니다.
class Clock extends StatefulWidget {
@override
_ClockState createState() => _ClockState();
}
class _ClockState extends State<Clock> {
@override
Widget build(BuildContext context) {
return Text("15:49", style: TextStyle(fontSize: 150),);
}
}
intl library import
이제 외부 라이브러리를 사용할 것입니다.
Flutter 의 외부 라이브러리는 pub.dev 를 통해 모두 탐색할 수 있습니다. 이번에는 여기서 ‘intl’ 이라는 라이브러리를 사용할 것입니다.
위 사이트에서 ‘intl’ 을 검색하여 선택해 줍니다. (intl pub.dev 사이트)
이후 installing 탭을 눌러 dependecies :
밑에 작성된 코드를 복사해 줍니다.
다음으로 pubspec.yaml
파일에 들어가 아래와 같은 코드를 찾아 복사한 코드를 붙여넣기 해 줍니다.
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
# TODO: 아래와 같이 붙여넣기 해 줍니다.
intl: ^0.17.0
다음으로 오른쪽 상단의 Pub get
버튼 또는 terminal 에 flutter pub get
을 작성하여 실행해 줍니다. 그러면 프로젝트에서 intl
라이브러리를 사용할 수 있게 됩니다.
Clock Widget 작성
main.dart
파일의 가장 위에 아래 코드를 작성해 줍니다.
import 'package:intl/intl_browser.dart';
import 'dart:async';
dart:async
는 Flutter 에서 Timer 기능을 사용하게 해주고, intl
라이브러리는 얻어온 값을 원하는 형태로 변경할 수 있도록 해 줍니다.
다음으로, Clock 에서 변수 2개를 생성해 줍니다. _timer
는 주기적으로 특정 함수를 실행시켜 주고, _timeString
은 현재 시간을 String 타입으로 표현한 것입니다.
class _ClockState extends State<Clock> {
String _timeString;
Timer _timer;
@override
Widget build(BuildContext context) {
return Text(_timeString, style: TextStyle(fontSize: 150),);
}
}
그리고 _ClockState 안에 initState
함수를 Override
하여 아래와 같이 작성해 줍니다. 이는 해당 class 안에서 initState
를 작성할 때 나오는 자동완성을 통해 작성가능합니다.
@override
void initState() {
_timeString = _formatDateTime(DateTime.now());
_timer = Timer.periodic(Duration(seconds: 1), (Timer t) => _getTime());
super.initState();
}
initState
는 StatefulWidget
이 실행될 때 딱 1번 실행되며, 여기서는 이 때 변수들에 초기값을 주도록 하였습니다. 또한 Timer 는 입력된 Duration (여기서는 1초) 마다 입력받은 함수 (여기서는 (Timer t) => _getTime()
) 을 실행하는 역할을 합니다.
이제 같은방식으로 dispose
함수를 Override
하여 아래와 같이 작성해 줍니다.
@override
void dispose() {
_timer.cancel();
super.dispose();
}
dispose
는 StatefulWidget
이 끝나게 되면 동작하며, 여기서는 _timer
변수에 들어간 Timer 클래스 사용을 중단하여, 메모리 소모를 하지 않도록 하였습니다. 이는 주로 메모리를 많이 사용하는 변수에 대해서 사용하는 방법입니다.
다음은 현재 시간을 받아오는 함수입니다.
void _getTime() {
final DateTime now = DateTime.now();
final String formattedDateTime = _formatDateTime(now);
setState(() {
_timeString = formattedDateTime;
});
}
String _formatDateTime(DateTime dateTime) {
return DateFormat('HH:mm').format(dateTime);
}
DateTime.now()
는 현재 시간을 받아오고,
_formatDateTime
함수의 DateFormat('HH:mm').format(dateTime)
은 intl
에서 지원하는 함수로 ‘HH:mm’ (24시간 형태) 의 String 타입으로 dateTime
를 변경하는 것입니다.
setState()
는 StatefulWidget
의 새로고침과 같은 역할로, 안에 있는 함수를 실행하게 되는데, 여기서는 _timeString
값에 formattedDateTime
을 주도록 하였습니다.
위 코드가 동작하는 과정을 간단히 다시 설명하면 아래와 같습니다.
- initState 에서 현재시간을
_timeString
에 저장, Timer 를 생성 - Timer 는 1초 마다,
_getTime()
실행 - 현재 시간을 ‘HH:mm’ 형태로 변경
_timeString
에 결과를 저장build
함수에서 Text 를 통해_timeString
을 화면에 표시- Widget 종료시 Timer 종료
전체 코드는 다음과 같습니다.
class Clock extends StatefulWidget {
@override
_ClockState createState() => _ClockState();
}
class _ClockState extends State<Clock> {
String _timeString;
Timer _timer;
@override
void initState() {
_timeString = _formatDateTime(DateTime.now());
_timer = Timer.periodic(Duration(seconds: 1), (Timer t) => _getTime());
super.initState();
}
@override
void dispose() {
_timer.cancel();
super.dispose();
}
void _getTime() {
final DateTime now = DateTime.now();
final String formattedDateTime = _formatDateTime(now);
setState(() {
_timeString = formattedDateTime;
});
}
String _formatDateTime(DateTime dateTime) {
return DateFormat('HH:mm').format(dateTime);
}
@override
Widget build(BuildContext context) {
return Text(_timeString, style: TextStyle(fontSize: 150),);
}
}
아래는 결과입니다.