Menu
CoddyTech

מעקב הרגלים: סימון יום

חלק מהיחידה פרויקטים במסלול ה-Flutter של Coddy. שיעור 30 מתוך 36.

יש להקיש על עיגול כדי לסמן את היום, ולהקיש עליו שוב כדי לבטל את הסימון. ההרגלים נמצאים במצב של המסך, אבל העיגול מצויר עמוק בתוך HabitCard. ההקשה צריכה לעבור למעלה, אל המקום שבו נמצאים הנתונים.

כך מעלים את המצב בעזרת פונקציות callback. המסך אחראי לשינוי:

void _toggle(Habit habit, int day) {
  setState(() {
    habit.days[day] = !habit.days[day];
  });
}

הוא מעביר לכל כרטיס פונקציה, onToggle: (day) => _toggle(habit, day). הטיפוס של הפונקציה בכרטיס הוא void Function(int day), פונקציה שמקבלת את מספר היום. כל עיגול מקבל VoidCallback פשוט, onTap: () => onToggle(i), ועוטף את ה-Container שלו ב-GestureDetector שקורא לה.

!habit.days[day] הופך ערך bool: true הופך ל-false ולהפך, כך שפונקציה אחת גם מסמנת וגם מבטלת את הסימון.

challenge icon

אתגר

קשה

סמנו ימים:

  • הוסיפו את המתודה _toggle למצב של המסך
  • הוסיפו ל־HabitCard את onToggle מסוג void Function(int day) בתור required, והעבירו את (day) => _toggle(habit, day)
  • הוסיפו ל־DayCircle את VoidCallback onTap בתור required, עטפו את ה־Container שלו ב־GestureDetector, והעבירו את () => onToggle(i)

נסו בעצמכם

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),
            const SizedBox(height: 12),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                for (int i = 0; i < 7; i++) DayCircle(label: dayNames[i], done: habit.days[i]),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class DayCircle extends StatelessWidget {
  const DayCircle({super.key, required this.label, required this.done});

  final String label;
  final bool done;

  @override
  Widget build(BuildContext context) {
    final colors = Theme.of(context).colorScheme;
    return Container(
      width: 40,
      height: 40,
      alignment: Alignment.center,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        color: done ? colors.primary : colors.surfaceContainerHighest,
      ),
      child: Text(
        label,
        style: TextStyle(
          fontSize: 11,
          fontWeight: FontWeight.bold,
          color: done ? colors.onPrimary : colors.onSurfaceVariant,
        ),
      ),
    );
  }
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה פרויקטים

תרגלו בעצמכם: קומפיילר Flutter אונליין