Menu
CoddyTech

습관 추적기: 한 주

Coddy Flutter 여정의 프로젝트 섹션에 포함된 레슨. 36개 중 29번째.

각 이름 아래에는 일주일이 표시됩니다. 월요일부터 일요일까지 작은 원 일곱 개가 있고, 해당하는 일을 한 날에는 원이 채워집니다. 각 원은 레이블과 완료 여부를 표시하는 DayCircle라는 작은 위젯입니다.

원은 크기가 고정된 Container이며, shape가 BoxShape.circle인 BoxDecoration을 사용합니다. 색상은 테마에서 가져오므로 앱의 녹색과 어울리고, 나중에 다크 모드에서는 색상이 자동으로 바뀝니다.

final colors = Theme.of(context).colorScheme;
...
color: done ? colors.primary : colors.surfaceContainerHighest,

색이 있는 배경 위의 텍스트는 색상 구성표에서 어울리는 색을 사용합니다. primary에는 onPrimary를, 회색에는 onSurfaceVariant를 사용합니다. 두 색을 짝지으면 텍스트를 언제나 읽기 쉽습니다.

원 일곱 개는 MainAxisAlignment.spaceBetween을 사용하는 Row로 배치하여 카드 전체에 고르게 펼쳐집니다. 횟수를 세는 for 반복문으로 원을 만들면 됩니다. dayNames[i]는 레이블이고, habit.days[i]는 완료 여부입니다.

challenge icon

챌린지

중급

한 주를 표시하세요:

  • required label과 done을 사용하는 DayCircle 위젯을 작성하세요. 완료된 경우 primary, 완료되지 않은 경우 surfaceContainerHighest를 사용하는 40×40 크기의 원을 만들고, 가운데에 굵기 11 크기의 라벨을 onPrimary 또는 onSurfaceVariant 색상으로 표시하세요.
  • HabitCard에서 이름 아래에 12픽셀 간격을 두고, spaceBetween으로 펼쳐진 Row에 DayCircle 7개를 추가하세요.

직접 해보기

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
      ),
      home: const HabitScreen(),
    );
  }
}

const List<String> dayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];

class Habit {
  Habit(this.name, this.days);

  final String name;
  final List<bool> days;
}

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

  @override
  State<HabitScreen> createState() => _HabitScreenState();
}

class _HabitScreenState extends State<HabitScreen> {
  final List<Habit> _habits = [
    Habit('Drink water', [true, true, true, false, true, false, false]),
    Habit('Read 10 pages', [true, false, true, true, false, false, false]),
    Habit('Stretch', List.filled(7, false)),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Habits')),
      body: ListView(
        padding: const EdgeInsets.fromLTRB(16, 8, 16, 88),
        children: [
          for (Habit habit in _habits) HabitCard(habit: habit),
        ],
      ),
    );
  }
}

class HabitCard extends StatelessWidget {
  const HabitCard({super.key, required this.habit});

  final Habit habit;

  @override
  Widget build(BuildContext context) {
    final textTheme = Theme.of(context).textTheme;
    return Card(
      margin: const EdgeInsets.only(top: 12),
      clipBehavior: Clip.antiAlias,
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(habit.name, style: textTheme.titleMedium),
          ],
        ),
      ),
    );
  }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

프로젝트의 모든 레슨

직접 연습해 보세요: 온라인 Flutter 컴파일러