나만의 개발노트

[Flutter] flexible, alignment, expanded, Timer, Duration 본문

[Flutter]/[Flutter]

[Flutter] flexible, alignment, expanded, Timer, Duration

노트포미 2024. 7. 24. 03:32

[flexible]

: UI를 비율에 기반해서 더 유연하게 조절할 수 있게 해주는 위젯

  • 비율은 속성 flex의 값에 지정
  • framework와 flutter엔진이 알아서 크기 계산
...
  Flexible(
    flex: 1,
    child: Container(
      color: Colors.red,
    ),
  ),
  Flexible(
    flex: 3,
    child: Container(
      color: Colors.blue,
    ),
  ),
...

 

(실행 시 화면)

 

 

 

 


[Alignment]

: Container위젯의 속성으로, Container내부에서의 위치를 지정하는 속성

Container(
	alignment: Alignment.center,
    ...
),

[expanded]

: 페이지를 확장하는 위젯


[Timer]

: 비동기적으로 특정 작업을 일정 시간 후에 실행하거나, 주기적으로 실행할 수 있는 기능을 제공

  • Dart 표준 라이브러리의 dart:async패키지에 포함됨

<사용법>

1. 단일 실행 타이머 : 지정된 시간이 지난 후 단 한 번 실행됨

Timer(Duration duration, void Function() callback)
//지정된 duration이 지난 후 callback 함수가 한 번 호출됨
Timer(Duration(seconds: 5), () {
  print("5초 후 실행");
});

 

2. 주기적 실행 타이머 : 지정된 간격으로 반복 실행됨

Timer.periodic(Duration duration, void Function(Timer) callback)
//지정된 duration 간격으로 callback 함수가 반복 호출됨 
//callback 함수는 타이머 인스턴스를 매개변수로 받는다 
Timer.periodic(Duration(seconds: 1), (Timer timer) {
  print("1초마다 실행");
});

 

3. cancel() : 타이머를 취소한다. 

Timer timer = Timer(Duration(seconds: 5), () {
  print("5초 후 실행");
});

// 타이머 취소
timer.cancel();

 

  • 타이머가 실행되는 동안에 메모리가 해제되지 않으므로, 필요하지 않을 때는 반드시 cancel() 호출하여 타이머 취소하기

[Duration]

: 시간 간격을 밀리초, 초, 분, 시간, 일 등의 단위로 나타낼 수 있다.

  • dart:core에 포함되어 있음
  • flutter 어플리케이션에서 애니메이션, 타이머, 지연 시간 등을 설정할 때 주로 사용

<생성자>

Duration({int days = 0, int hours = 0, int minutes = 0, int seconds = 0, int milliseconds = 0, int microseconds = 0})

[문제]

: 아래 영상처럼 작동하는 코드 작성하기

 

<추가 필요 사항>

- 시간이 끝나면, ROUND 숫자가 1 올라가고 시간초는 원상복구

- 타이머 작동중 reset 버튼은 동작X


[정답]

import 'dart:async';

import 'package:flutter/material.dart';

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

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  static const twentyFiveMins = 1500;
  int totalSeconds = twentyFiveMins;
  int round = 0;
  late Timer timer;
  bool isRunning = false; //진행중인지 확인하는 매크로

  //1초마다 호출되는 메소드
  void onTick(Timer timer) {
    print('onTick called');
    setState(() {
      if (totalSeconds == 0) {
        round += 1;
        totalSeconds = twentyFiveMins;
        isRunning = false;
        timer.cancel();
      } else {
        totalSeconds -= 1;
      }
    });
  }

  //버튼 눌리면 실행되는 메소드
  void onStartPressed() {
    print('onStartPressed called');
    //timer은 객체 참조
    //Timer.period는 비동기적으로 동작함 -> onStartPressed함수의 종료와 상관 없이 동작함(별도의 이벤트 루프)
    //onTick()이 아니라 onTick인 이유 : 함수 참조 전달 -> Timer.periodic메소드가 onTick함수를 호출하도록 설정vs 함수 호출 전달-> Timer.periodic메소드를 호출할 때 onTick함수가 즉시 실행되고, 반환값이 콜백으로 전달 됨 = void반환하므로 옳지 않음
    timer = Timer.periodic(const Duration(seconds: 1), onTick);
    setState(() {
      isRunning = true;
    });
  }

  void onPausePressed() {
    print('onPausePressed called');
    timer.cancel();
    setState(() {
      isRunning = false;
    });
    print('onPausePressed end');
  }

  void onResetPressed() {
    setState(() {
      totalSeconds = twentyFiveMins;
      isRunning = false;
      timer.cancel();
    });
  }

  String format(int seconds) {
    print('format called');
    var duration = Duration(seconds: seconds);
    return duration.toString().substring(2, 7);
  }

  @override
  Widget build(BuildContext context) {
    print('build called');
    return Scaffold(
      body: Column(
        children: [
          Flexible(
            flex: 3,
            child: Container(
              alignment: Alignment.bottomCenter,
              child: Text(
                format(totalSeconds),
                style: TextStyle(
                    fontSize: 80,
                    fontWeight: FontWeight.w800,
                    color: Theme.of(context).cardColor),
              ),
            ),
          ),
          Flexible(
            flex: 4,
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  IconButton(
                    onPressed: isRunning ? onPausePressed : onStartPressed,
                    icon: isRunning
                        ? Icon(
                            Icons.pause_circle_outline,
                            size: 120,
                            color: Theme.of(context).cardColor,
                          )
                        : Icon(
                            Icons.play_circle_outline,
                            size: 120,
                            color: Theme.of(context).cardColor,
                          ),
                  ),
                  TextButton(
                    onPressed: isRunning ? () {} : onResetPressed,
                    child: Text(
                      'reset',
                      style: TextStyle(
                        fontSize: 20,
                        color: Theme.of(context).cardColor,
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
          Flexible(
            flex: 2,
            child: Container(
              decoration: BoxDecoration(
                color: Theme.of(context).cardColor,
                borderRadius: BorderRadius.circular(50),
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(
                        'ROUND',
                        style: TextStyle(
                            fontSize: 23,
                            fontWeight: FontWeight.w500,
                            color: Theme.of(context)
                                .textTheme
                                .headlineLarge!
                                .color),
                      ),
                      const SizedBox(
                        height: 10,
                      ),
                      Row(
                        children: [
                          Text(
                            '$round',
                            style: TextStyle(
                                fontSize: 35,
                                fontWeight: FontWeight.w700,
                                color: Theme.of(context)
                                    .textTheme
                                    .headlineLarge!
                                    .color),
                          ),
                          Transform.translate(
                            offset: const Offset(10, 10),
                            child: Text(
                              '/4',
                              style: TextStyle(
                                  fontSize: 17,
                                  fontWeight: FontWeight.w300,
                                  color: Theme.of(context)
                                      .textTheme
                                      .headlineLarge!
                                      .color),
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                  VerticalDivider(
                    thickness: 1.5,
                    color: Theme.of(context).textTheme.headlineLarge!.color,
                    indent: 20,
                    endIndent: 40,
                  ),
                  Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(
                        'GOAL',
                        style: TextStyle(
                            fontSize: 23,
                            fontWeight: FontWeight.w500,
                            color: Theme.of(context)
                                .textTheme
                                .headlineLarge!
                                .color),
                      ),
                      const SizedBox(
                        height: 10,
                      ),
                      Row(
                        children: [
                          Text(
                            '1',
                            style: TextStyle(
                                fontSize: 35,
                                fontWeight: FontWeight.w700,
                                color: Theme.of(context)
                                    .textTheme
                                    .headlineLarge!
                                    .color),
                          ),
                          Transform.translate(
                            offset: const Offset(10, 10),
                            child: Text(
                              '/4',
                              style: TextStyle(
                                  fontSize: 17,
                                  fontWeight: FontWeight.w300,
                                  color: Theme.of(context)
                                      .textTheme
                                      .headlineLarge!
                                      .color),
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}