Kodokon kodokon.com

السِّمات: ThemeData وMaterial 3 والوضع الداكن

اجمع الألوان والطباعة مركزيًا في ThemeData، وولِّد لوحة ألوان Material 3 باستخدام ColorScheme.fromSeed، وقدّم وضعًا داكنًا دون عناء.

9 دقيقة · 3 أسئلة

افتح هذا الدرس في Kodokon

إن التوقّف عن تنسيق كل ويدجت على حدة مرحلة احترافية: إذ يجمع ThemeData الألوان والطباعة والأشكال للتطبيق بأكمله في مكان مركزي. ومع Material 3 (المُفعَّل افتراضيًا منذ Flutter 3.16)، ينطلق كل شيء من ColorScheme: يشتقّ ColorScheme.fromSeed لوحة ألوان كاملة ومتناسقة وسهلة الوصول من لون بذرة (seed) واحد.

DART
import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    const seed = Colors.teal;
    return MaterialApp(
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: seed,
        ),
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: seed,
          brightness: Brightness.dark,
        ),
      ),
      themeMode: ThemeMode.system,
      home: Scaffold(
        appBar: AppBar(title: const Text('Shop')),
        body: const Center(child: Text('Welcome')),
      ),
    );
  }
}
سِمتان مُولَّدتان من لون بذرة واحد.

داخل ويدجاتك، لا تُعِد اختراع أيّ شيء: اقرأ السِّمة المحيطة باستخدام Theme.of(context). يكشف colorScheme عن أدوار دلالية (primary وonPrimary وprimaryContainer وsurface وما إلى ذلك)، ويكشف textTheme عن أنماط مُسمّاة (titleMedium وbodyLarge وما إلى ذلك). ويتكيّف الويدجت المكتوب بهذه الطريقة تلقائيًا مع السِّمة الفاتحة وكذلك الداكنة.

DART
import 'package:flutter/material.dart';

class PriceTag extends StatelessWidget {
  const PriceTag({super.key, required this.price});

  final double price;

  @override
  Widget build(BuildContext context) {
    final colors = Theme.of(context).colorScheme;
    final text = Theme.of(context).textTheme;
    return Container(
      padding: const EdgeInsets.symmetric(
        horizontal: 12,
        vertical: 6,
      ),
      decoration: BoxDecoration(
        color: colors.primaryContainer,
        borderRadius: BorderRadius.circular(8),
      ),
      child: Text(
        '$price €',
        style: text.titleMedium?.copyWith(
          color: colors.onPrimaryContainer,
        ),
      ),
    );
  }
}
لا لون مُضمَّن بشكل ثابت: يتبع الويدجت السِّمة النشطة.

للمضيّ أبعد، اضبط سِمات المكوّنات: تقبل كل عائلة من الويدجات (أشرطة التطبيق، والأزرار، وحقول الإدخال) سِمة مخصّصة في ThemeData. تُعرِّف الحاشية الداخلية لأزرارك أو توسيط عناوينك مرة واحدة، فترث كل نسخة ذلك دون نمط محلي واحد.

DART
import 'package:flutter/material.dart';

final ThemeData appTheme = ThemeData(
  colorScheme: ColorScheme.fromSeed(
    seedColor: Colors.teal,
  ),
  appBarTheme: const AppBarTheme(
    centerTitle: true,
    elevation: 0,
  ),
  filledButtonTheme: FilledButtonThemeData(
    style: FilledButton.styleFrom(
      padding: const EdgeInsets.symmetric(
        horizontal: 24,
        vertical: 12,
      ),
    ),
  ),
);
تُطبَّق إعدادات المكوّنات في التطبيق بأكمله.

اختبار المعرفة

تأكّد من أنك تذكّرت النقاط الأساسية في هذا الدرس.

  1. ماذا يُنتِج ColorScheme.fromSeed(seedColor: ...)؟
    • لونًا واحدًا مُفتَّحًا قليلًا
    • لوحة ألوان Material 3 كاملة ومتماسكة مشتقّة من لون البذرة
    • تدرّجًا لونيًا للخلفيات
    • سِمة داكنة فقط
  2. كيف تجعل التطبيق يتبع إعداد النظام الفاتح/الداكن؟
    • قدّم theme فقط؛ والباقي تلقائي
    • قدّم theme وdarkTheme، واضبط themeMode على ThemeMode.system
    • استدعِ setState عند تغيّر السطوع
    • اقرأ MediaQuery في كل ويدجت
  3. لماذا تكتب color: Theme.of(context).colorScheme.primary بدلًا من color: Colors.blue؟
    • إنها أقصر في الكتابة
    • يتكيّف اللون مع السِّمة النشطة ويظل متسقًا في التطبيق بأكمله
    • إن Colors.blue مُهمَل في Material 3