Flutter: مقدمة في Flutter وإعداد البيئة
يتيح لك Flutter بناء تطبيقات iOS وAndroid وWeb وDesktop بقاعدة كود Dart واحدة — كاستخدام مفتاح رئيسي لفتح أربع أبواب.
📋 المتطلبات السابقة: لا حاجة لأي خبرة مسبقة
1. ما ستتعلمه
- بنية إطار عمل Flutter وعلاقته بلغة Dart
- مبادئ عرض شجرة الويدجت (كل شيء هو ويدجت)
- ميزات Flutter 3.x الجديدة: محرك عرض Impeller، دعم الأجهزة القابلة للطي
- تثبيت Flutter SDK وإعداد PATH على Windows/macOS/Linux
- التحقق من سير العمل الكامل باستخدام
flutter createوflutter runوflutter doctor
2. قصة حقيقية من رائد أعمال
(1) المشكلة: أربع منصات، أربع قواعد كود
بوب هو رائد أعمال يحتاج مشروعه ShopApp للتجارة الإلكترونية أن يغطي iOS وAndroid وWeb وDesktop في وقت واحد. إذا احتاجت كل منصة قاعدة كود خاصة بها، فسيحتاج إلى 4 فرق تطوير و4 قواعد كود، بتكلفة شخصية تتجاوز 500 ألف دولار سنويًا. والأخطر، أن الحملة الترويجية تستغرق 6 أسابيع من المتطلبات إلى الإطلاق — لأن كل فريق يجب أن ينفذها بشكل مستقل.
(2) حل Flutter
يعتمد Flutter استراتيجية "اكتب مرة، شغّل في أي مكان"، باستخدام Dart لكتابة طبقة واجهة المستخدم وعرض البكسلات مباشرة عبر محرك الرسم المخصص، دون الاعتماد على مكونات واجهة المستخدم الأصلية.
import 'package:flutter/material.dart';
// One codebase, four platforms
void main() => runApp(const ShopApp());
class ShopApp extends StatelessWidget {
const ShopApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ShopApp',
home: Scaffold(
appBar: AppBar(title: const Text('ShopApp')),
body: const Center(child: Text('Hello, Bob!')),
),
);
}
}
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
(3) النتيجة: فريق واحد يحل محل أربعة
بعد اعتماد Flutter، يحتفظ فريق بوب الواحد بقاعدة كود واحدة، ويطلق على جميع المنصات الأربعة في وقت واحد. انخفضت مدة الحملات الترويجية من 6 أسابيع إلى أسبوع واحد، وانخفضت تكاليف التطوير السنوية من 500 ألف دولار إلى 150 ألف دولار.
3. البنية التقنية لـ Flutter
يستخدم Flutter بنية طبقية، من إطار العمل العلوي إلى المحرك السفلي، لكل طبقة مسؤولياتها.
graph TD
A[Flutter SDK] --> B[Dart SDK]
A --> C[Framework Layer]
A --> D[Engine Layer]
C --> E[Material Library]
C --> F[Cupertino Library]
D --> G[Skia / Impeller]
D --> H[Platform Embedder]
H --> I[Android]
H --> J[iOS]
H --> K[Web]
H --> L[Windows/macOS/Linux]
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
(1) طبقة إطار العمل
طبقة إطار العمل هي ما يتفاعل معه المطورون مباشرة، وهي مكتوبة بالكامل بلغة Dart:
- طبقة الويدجت: أوصاف واجهة تعريفية (StatelessWidget / StatefulWidget)
- طبقة العنصر: كائنات مُنشأة من الويدجت، تدير بنية الشجرة
- طبقة RenderObject: مسؤولة عن القياس والتخطيط والرسم
| الطبقة | المسؤولية | اللغة |
|---|---|---|
| الويدجت | تعريف إعدادات واجهة المستخدم | Dart |
| العنصر | إدارة فرق شجرة الويدجت | Dart |
| RenderObject | التخطيط والرسم | Dart |
| المحرك | العرض والإدخال/الإخراج | C++ |
(2) طبقة المحرك
طبقة المحرك مكتوبة بلغة C++، وتشمل المكونات الأساسية:
- Skia / Impeller: محرك عرض رسوميات ثنائي الأبعاد، يحوّل تعليمات واجهة المستخدم من Dart إلى تعليمات GPU
- Dart Runtime: تجميع JIT (التطوير) وAOT (الإنتاج)
- Platform Embedder: طبقة التضمين الخاصة بالمنصة، تدير حلقات الأحداث والخيوط
(3) Platform Embedder
لكل منصة تنفيذ Embedder مختلف، مسؤول عن:
| المنصة | Embedder | طريقة العرض |
|---|---|---|
| Android | flutter_shell (Java/Kotlin) |
GPU (Vulkan/OpenGL) |
| iOS | FlutterViewController (Swift/ObjC) |
GPU (Metal) |
| Web | HTML Canvas / WebGL | CanvasKit / HTML renderer |
| Desktop | GLFW / Win32 / Cocoa | GPU |
4. كل شيء هو ويدجت
الفلسفة الأساسية لـ Flutter: كل شيء هو ويدجت. الأزرار والخطوط والمسافات وحتى قيود التخطيط كلها ويدجت.
(1) تصنيفات الويدجت
| النوع | الوصف | أمثلة |
|---|---|---|
| StatelessWidget | غير قابل للتغيير، يُبنى مرة واحدة | Text, Icon, Image |
| StatefulWidget | ذو حالة قابلة للتغيير، يمكن إعادة بنائه | TextField, Checkbox |
| RenderObjectWidget | يتحكم في التخطيط والرسم | Flex, Stack, Positioned |
| ProxyWidget | يمرر بيانات إلى الشجرة الفرعية | InheritedWidget, Provider |
▶ مثال
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
: بطاقة منتج StatelessWidget
import 'package:flutter/material.dart';
class ProductCard extends StatelessWidget {
final String name;
final double price;
const ProductCard({
super.key,
required this.name,
required this.price,
});
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(name, style: const TextStyle(fontSize: 18)),
Text('\$${price.toStringAsFixed(2)}',
style: const TextStyle(color: Colors.green, fontSize: 16)),
],
),
),
);
}
}
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
▶ مثال
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
: عداد StatefulWidget
import 'package:flutter/material.dart';
class QuantitySelector extends StatefulWidget {
const QuantitySelector({super.key});
@override
State<QuantitySelector> createState() => _QuantitySelectorState();
}
class _QuantitySelectorState extends State<QuantitySelector> {
int _count = 1;
@override
Widget build(BuildContext context) {
return Row(
children: [
IconButton(
icon: const Icon(Icons.remove),
onPressed: () => setState(() => _count = (_count - 1).clamp(1, 99)),
),
Text('$_count', style: const TextStyle(fontSize: 20)),
IconButton(
icon: const Icon(Icons.add),
onPressed: () => setState(() => _count++),
),
],
);
}
}
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
5. إعداد البيئة
(1) تثبيت Flutter SDK
| الخطوة | Windows | macOS | Linux |
|---|---|---|---|
| تحميل SDK | flutter.dev/docs/get-started/install/windows | flutter.dev/docs/get-started/install/macos | flutter.dev/docs/get-started/install/linux |
| مسار الاستخراج | C:\flutter |
~/development/flutter |
~/development/flutter |
| إعداد PATH | أضف إلى متغيرات البيئة | أضف إلى ~/.zshrc |
أضف إلى ~/.bashrc |
▶ مثال
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
: إعداد PATH (macOS/Linux)
# Add Flutter to PATH in ~/.zshrc or ~/.bashrc
export PATH="$HOME/development/flutter/bin:$PATH"
# Verify installation
flutter --version
# Output: Flutter 3.x.x • channel stable
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
▶ مثال
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
: فحص flutter doctor
# Run doctor to check all dependencies
flutter doctor
# Expected output:
# [✓] Flutter (Channel stable, 3.x.x)
# [✓] Android toolchain
# [✓] Chrome - develop for the web
# [✓] Android Studio
# [!] VS Code (install Flutter extension)
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
(2) إعداد بيئة التطوير
| بيئة التطوير | الإضافات المطلوبة | الإضافات الموصى بها |
|---|---|---|
| VS Code | Flutter, Dart | Flutter Widget Snippets, Error Lens |
| Android Studio | Flutter, Dart | Flutter Intl, Riverpod Snippet |
▶ مثال
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
: إنشاء مشروعك الأول
# Create a new Flutter project
flutter create shop_app
# Navigate to project directory
cd shop_app
# Run on connected device or emulator
flutter run
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
6. أول Hello World
▶ مثال
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
: ShopApp Hello World
import 'package:flutter/material.dart';
void main() {
runApp(const ShopApp());
}
class ShopApp extends StatelessWidget {
const ShopApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'ShopApp',
theme: ThemeData(
colorSchemeSeed: Colors.blue,
useMaterial3: true,
),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('ShopApp')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.shopping_bag, size: 80, color: Colors.blue),
const SizedBox(height: 16),
const Text('Welcome to ShopApp!',
style: TextStyle(fontSize: 24)),
const SizedBox(height: 8),
Text('Million-level products, USD settlement',
style: TextStyle(fontSize: 14, color: Colors.grey[600])),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {},
child: const Text('Start Shopping'),
),
],
),
),
);
}
}
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
▶ مثال
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
: تجربة إعادة التحميل السريع
# Start app with hot reload support
flutter run
# After modifying code, press:
# r - Hot reload (keep state, update UI)
# R - Hot restart (reset state, rebuild)
# q - Quit
# Hot reload updates UI in <1 second
# Try: change 'Welcome to ShopApp!' to 'Hello Bob!'
# Press r → UI updates instantly
> **الإخراج:** شغّل محليًا باستخدام Flutter SDK (Flutter 3.x / Dart 3.x). خادم Piston لا يحتوي على Flutter؛ استخدم `flutter run` على جهازك المحلي للمقارنة. قد تختلف واجهة/حالة المستخدم الفعلية قليلاً بين المنصات.
7. ميزات Flutter 3.x الجديدة
| الميزة | الوصف | التأثير |
|---|---|---|
| محرك Impeller | شيدرات مُجمّعة مسبقًا، يزيل تأتأة الإطار الأول | تحسين أداء العرض بنسبة 30%+ |
| دعم الأجهزة القابلة للطي | تخطيط متكيف للشاشات القابلة للطي | توسيع تغطية الأجهزة |
| Material 3 | مواصفات تصميم جديدة، ألوان ديناميكية | واجهة أكثر حداثة |
| macOS / Linux مستقر | دعم رسمي لمنصات Desktop | تغطية كاملة لـ 4 منصات |
| محرك العرض | وقت الإطار الأول | تجميع الشيدرات | الإصدار المطبّق |
|---|---|---|---|
| Skia | 200-500ms | تجميع JIT في وقت التشغيل | Flutter 2.x |
| Impeller | <50ms | تجميع AOT في وقت البناء | Flutter 3.x |
❓ أسئلة شائعة
flutter doctor عن "Android licenses not accepted"؟flutter doctor --android-licenses واقبل كل ترخيص واحدًا تلو الآخر.📖 ملخص
- يستخدم Flutter بنية طبقية إطار عمل + محرك: إطار العمل بلغة Dart، والمحرك بلغة C++
- كل شيء هو ويدجت: StatelessWidget (غير قابل للتغيير) وStatefulWidget (ذو حالة قابلة للتغيير)
- إعداد البيئة في ثلاث خطوات: تثبيت SDK ← إعداد PATH ← تشغيل
flutter doctor flutter createلإنشاء المشاريع،flutter runلبدء التصحيح، وإعادة التحميل السريع للتحديثات دون الثانية- محرك Impeller في Flutter 3.x يزيل تأتأة الإطار الأول، وMaterial 3 يوفر تصميمًا عصريًا
📝 تمارين
- أساسي (الصعوبة ⭐): ثبّت Flutter SDK على حاسوبك، وشغّل
flutter doctor، وتأكد من نجاح 4 عناصر على الأقل. - متوسط (الصعوبة ⭐⭐): عدّل مثال Hello World لإضافة ويدجت Text تعرض التاريخ الحالي.
- متقدم (الصعوبة ⭐⭐⭐): أنشئ Column بثلاث بطاقات منتجات، كل واحدة تعرض اسم المنتج والسعر بالدولار. النقر على البطاقة يعرض معلومات المنتج باستخدام SnackBar.
← السابق | التالي →