متتبع العادات: الأسبوع
جزء من قسم المشاريع في رحلة Flutter على Coddy. الدرس 29 من 36.
تأتي أسفل كل اسم أيام الأسبوع: سبع دوائر صغيرة، من الاثنين إلى الأحد، تُملأ في الأيام التي أنجزت فيها العادة. كل دائرة عنصر واجهة صغير مستقل يُسمى DayCircle، وله تسمية وحالة توضّح ما إذا كان قد أُنجز.
الدائرة هي Container بحجم ثابت وBoxDecoration يكون shape فيه هو BoxShape.circle. يأتي لونها من السمة، لذا يتناسق مع اللون الأخضر للتطبيق، ثم يتغير تلقائيًا في الوضع الداكن:
final colors = Theme.of(context).colorScheme;
...
color: done ? colors.primary : colors.surfaceContainerHighest,يكون لون النص على خلفية ملوّنة متناسقًا مع ألوان السمة: استخدم onPrimary مع primary، وonSurfaceVariant مع اللون الرمادي. نسّق كل زوج معًا، وسيظل النص مقروءًا دائمًا.
الدوائر السبع هي Row مع MainAxisAlignment.spaceBetween، فتتوزع على امتداد البطاقة. أنشئها باستخدام حلقة for تعدادية: dayNames[i] هي التسمية، وhabit.days[i] تحدد ما إذا كان اليوم قد أُنجز.
التحدي
متوسطاعرض الأسبوع:
- اكتب عنصر واجهة
DayCircleمعrequiredوlabelوdone: دائرة أبعادها 40 × 40، بلونprimaryعند إتمامها وبلونsurfaceContainerHighestعند عدم إتمامها، مع توسيط التسمية بخط عريض حجمه 11، بلونonPrimaryأوonSurfaceVariant - في
HabitCard، أضف أسفل الاسم وبعد مسافة مقدارها 12 بكسل صفًاRowموزعًا باستخدامspaceBetween، ويضم سبعة عناصرDayCircle
جرّب بنفسك
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),
],
),
),
);
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس المشاريع
تدرّب بنفسك: مترجم Flutter عبر الإنترنت