مقدمة في Flutter

ما هو Flutter؟

Flutter هو إطار عمل مفتوح المصدر من Google لتطوير تطبيقات الموبايل متعددة المنصات باستخدام لغة Dart.

مميزات Flutter:
  • تطوير سريع: Hot Reload للتحديث الفوري للتطبيق
  • كود واحد: تطوير تطبيق واحد يعمل على iOS و Android
  • أداء عالي: تطبيقات بسرعة تطبيقات native
  • UI جميل: واجهات مستخدم عصرية وجذابة
  • مجتمع كبير: دعم قوي من Google والمجتمع
مكونات Flutter:
  • Flutter SDK: أدوات التطوير الأساسية
  • Dart Language: لغة البرمجة المستخدمة
  • Flutter Engine: محرك الرندرينغ
  • Widgets: مكونات بناء الواجهة
معلومة: Flutter يستخدم Widget-based architecture حيث كل شيء في Flutter هو Widget.

تثبيت Flutter SDK

خطوات التثبيت:

  1. قم بتحميل Flutter SDK من الموقع الرسمي
  2. استخرج الملفات في مجلد مناسب
  3. أضف Flutter إلى PATH
  4. قم بتشغيل: flutter doctor للتحقق
  5. ثبت Android Studio أو Xcode حسب المنصة
التحقق من التثبيت:
flutter doctor

يجب أن تظهر جميع العناصر بخضراء ✓ للتأكد من أن كل شيء مثبت بشكل صحيح.

لغة Dart الأساسية

مقدمة عن Dart:

Dart هي لغة برمجة كائنية التوجه طورتها Google، وهي سهلة التعلم ومشابهة للغات مثل Java و JavaScript.

أساسيات Dart:
// المتغيرات
String name = 'أحمد';
int age = 25;
double price = 99.99;
bool isActive = true;

// الدوال
void printName(String name) {
  print('الاسم: $name');
}

// Class
class Person {
  String name;
  int age;
  
  Person(this.name, this.age);
  
  void display() {
    print('$name, $age');
  }
}

إنشاء أول تطبيق

إنشاء مشروع جديد:

flutter create my_app
cd my_app
flutter run
بنية المشروع:
  • lib/main.dart: الملف الرئيسي
  • pubspec.yaml: ملف التبعيات
  • android/: ملفات Android
  • ios/: ملفات iOS

Widgets الأساسية

ما هي Widgets؟

كل شيء في Flutter هو Widget. Widgets هي مكونات بناء الواجهة.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('أول تطبيق')),
        body: Center(child: Text('مرحباً بFlutter!')),
      ),
    );
  }
}

StatelessWidget

StatelessWidget:

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text('نص ثابت');
  }
}

يستخدم للعناصر التي لا تتغير حالتها.

StatefulWidget

StatefulWidget:

class CounterWidget extends StatefulWidget {
  @override
  _CounterWidgetState createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  int count = 0;
  
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('العداد: $count'),
        ElevatedButton(
          onPressed: () {
            setState(() {
              count++;
            });
          },
          child: Text('زيادة'),
        ),
      ],
    );
  }
}

Layout Widgets

Widgets التخطيط:

  • Row: ترتيب أفقي
  • Column: ترتيب عمودي
  • Stack: تراكب العناصر
  • Container: حاوية قابلة للتخصيص

Row و Column

Row:

Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    Text('عنصر 1'),
    Text('عنصر 2'),
    Text('عنصر 3'),
  ],
)
Column:
Column(
  crossAxisAlignment: CrossAxisAlignment.start,
  children: [
    Text('عنصر 1'),
    Text('عنصر 2'),
  ],
)

Container و SizedBox

Container:

Container(
  width: 200,
  height: 100,
  color: Colors.blue,
  padding: EdgeInsets.all(16),
  child: Text('محتوى'),
)
SizedBox:
SizedBox(
  width: 100,
  height: 50,
  child: Text('نص'),
)

Text Widget

Text Widget:

Text(
  'مرحباً بFlutter',
  style: TextStyle(
    fontSize: 24,
    fontWeight: FontWeight.bold,
    color: Colors.blue,
  ),
)

Image Widget

عرض الصور:

// من Assets
Image.asset('assets/image.png')

// من Network
Image.network('https://example.com/image.jpg')

// من File
Image.file(File('path/to/image.jpg'))

Button Widgets

أنواع الأزرار:

ElevatedButton(
  onPressed: () {},
  child: Text('زر مرتفع'),
)

OutlinedButton(
  onPressed: () {},
  child: Text('زر محدد'),
)

TextButton(
  onPressed: () {},
  child: Text('زر نصي'),
)

TextField و Input

TextField:

TextField(
  decoration: InputDecoration(
    labelText: 'الاسم',
    hintText: 'أدخل اسمك',
  ),
  onChanged: (value) {
    print(value);
  },
)

ListView

ListView:

ListView(
  children: [
    ListTile(title: Text('عنصر 1')),
    ListTile(title: Text('عنصر 2')),
    ListTile(title: Text('عنصر 3')),
  ],
)

// ListView.builder
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ListTile(title: Text(items[index]));
  },
)

GridView

GridView:

GridView.builder(
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,
  ),
  itemCount: items.length,
  itemBuilder: (context, index) {
    return Card(child: Text(items[index]));
  },
)

Navigation

التنقل:

Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondScreen()),
);

// العودة
Navigator.pop(context);

Routes و Named Routes

Named Routes:

MaterialApp(
  routes: {
    '/': (context) => HomeScreen(),
    '/second': (context) => SecondScreen(),
  },
)

// استخدام
Navigator.pushNamed(context, '/second');

State Management الأساسيات

إدارة الحالة:

State Management يساعد في إدارة حالة التطبيق بشكل منظم. من الحلول الشائعة: Provider, Bloc, GetX.

Provider Package

استخدام Provider:

// في pubspec.yaml
dependencies:
  provider: ^6.0.0

// Provider
class CounterProvider extends ChangeNotifier {
  int count = 0;
  
  void increment() {
    count++;
    notifyListeners();
  }
}

// الاستخدام
Consumer<CounterProvider>(
  builder: (context, counter, child) {
    return Text('${counter.count}');
  },
)

HTTP Requests

طلبات HTTP:

import 'package:http/http.dart' as http;

Future<void> fetchData() async {
  var response = await http.get(
    Uri.parse('https://api.example.com/data'),
  );
  print(response.body);
}

JSON Parsing

تحليل JSON:

import 'dart:convert';

var jsonString = '{"name": "أحمد", "age": 25}';
var jsonData = jsonDecode(jsonString);
print(jsonData['name']); // أحمد

Local Storage

SharedPreferences:

import 'package:shared_preferences/shared_preferences.dart';

// حفظ
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('name', 'أحمد');

// قراءة
String? name = prefs.getString('name');

SQLite Database

SQLite:

import 'package:sqflite/sqflite.dart';

Future<Database> openDatabase() async {
  return await openDatabase(
    'my_database.db',
    version: 1,
    onCreate: (db, version) {
      db.execute('CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT)');
    },
  );
}

Animations

الحركات:

AnimatedContainer(
  duration: Duration(seconds: 1),
  width: isExpanded ? 200 : 100,
  height: isExpanded ? 200 : 100,
  color: Colors.blue,
)

Theme و Styling

الثيم:

MaterialApp(
  theme: ThemeData(
    primarySwatch: Colors.blue,
    fontFamily: 'Cairo',
  ),
)

Forms و Validation

النماذج:

final _formKey = GlobalKey<FormState>();

Form(
  key: _formKey,
  child: TextFormField(
    validator: (value) {
      if (value == null || value.isEmpty) {
        return 'يرجى إدخال القيمة';
      }
      return null;
    },
  ),
)

Publishing App

نشر التطبيق:

  1. قم ببناء APK: flutter build apk
  2. أو بناء App Bundle: flutter build appbundle
  3. للـ iOS: flutter build ios
  4. قم برفع الملف على Google Play أو App Store

Testing

الاختبارات:

// Unit Test
test('should add two numbers', () {
  expect(add(2, 3), 5);
});

// Widget Test
testWidgets('should display text', (WidgetTester tester) async {
  await tester.pumpWidget(MyWidget());
  expect(find.text('Hello'), findsOneWidget);
});

مشروع تطبيقي شامل

تطبيق Todo List:

class TodoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: TodoListScreen(),
    );
  }
}

class TodoListScreen extends StatefulWidget {
  @override
  _TodoListScreenState createState() => _TodoListScreenState();
}

class _TodoListScreenState extends State<TodoListScreen> {
  List<String> todos = [];
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('قائمة المهام')),
      body: ListView.builder(
        itemCount: todos.length,
        itemBuilder: (context, index) {
          return ListTile(title: Text(todos[index]));
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // إضافة مهمة جديدة
        },
        child: Icon(Icons.add),
      ),
    );
  }
}