Menu
CoddyTech

Tracker delle abitudini: segna un giorno

Fa parte della sezione Progetti del percorso Flutter di Coddy. Lezione 30 di 36.

Tocca un cerchio per contrassegnare il giorno, toccalo di nuovo per deselezionarlo. Le abitudini sono nello stato della schermata, ma il cerchio viene disegnato all'interno di un HabitCard. Il tocco deve risalire fino al punto in cui si trovano i dati.

Questo è sollevare lo stato usando le callback. La schermata gestisce la modifica:

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

Passa a ogni scheda una funzione, onToggle: (day) => _toggle(habit, day). Il tipo della scheda per questa funzione è void Function(int day), una funzione che accetta il numero del giorno. Ogni cerchio riceve una semplice VoidCallback, onTap: () => onToggle(i), e racchiude il suo Container in un GestureDetector che la chiama.

!habit.days[day] inverte un bool: true diventa false e viceversa, quindi una sola funzione contrassegna e deseleziona.

challenge icon

Sfida

Difficile

Spunta i giorni:

  • aggiungi il metodo _toggle allo stato della schermata
  • assegna a HabitCard un onToggle required di tipo void Function(int day) e passa (day) => _toggle(habit, day)
  • assegna a DayCircle un VoidCallback onTap required, racchiudi il suo Container in un GestureDetector e passa () => onToggle(i)

Provalo tu

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 iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Progetti

Esercitati da solo: Compilatore Flutter online