تطوير تطبيقات Flutter
ما هو مطور Flutter؟
مطور Flutter
مطور Flutter يركز على إنشاء تطبيقات متعددة المنصات باستخدام Dart مع الاستفادة من أدوات مثل Flutter SDK، Material Design، Firebase وتوفير تجربة مستخدم متميزة على Android و iOS.
متعددة المنصات
تطبيقات تعمل على Android، iOS، Web، Desktop
Dart Language
لغة برمجة حديثة وسريعة
Material Design
واجهات مستخدم جميلة ومتسقة
أداء عالي
60 إطار في الثانية، تجربة سلسة
اللغات والأدوات المستخدمة
Dart
اللغة الأساسية التي تعمل عليها Flutter، لغة برمجة حديثة وفعالة
XML/JSON
تنسيق البيانات عند التعامل مع APIs أو قواعد البيانات
SQL
إدارة قواعد البيانات المحلية باستخدام SQLite
Flutter SDK
مجموعة أدوات Google الرسمية لتطوير التطبيقات
VS Code / Android Studio
بيئة التطوير المتكاملة (IDE) لكتابة وتشغيل التطبيقات
Firebase
منصة شاملة توفر خدمات التخزين السحابي، التوثيق والإشعارات
مهارات مطور Flutter
Dart Programming
إتقان أساسيات لغة Dart المتقدمة
Flutter Widgets
فهم المكونات والويجتات الأساسية
State Management
إدارة حالة التطبيق باستخدام Provider/Bloc
Material Design
تصميم واجهات وفق معايير Google
Firebase Integration
التكامل مع خدمات الخلفية السحابية
Animations
إنشاء رسوم متحركة معقدة وديناميكية
خارطة التعلم خطوة بخطوة
الخطوة 1: تعلم Dart
Dart هي اللغة الأساسية التي تعمل عليها Flutter، وهي لغة برمجة حديثة وفعالة
الأهمية:
الأساس لفهم كيفية كتابة شيفرات نظيفة وفعالة
الأدوات:
أي محرر نصوص مثل VS Code
مثال Dart أساسي:
// أساسيات لغة Dart
void main() {
print("مرحباً بالعالم!");
// المتغيرات والثوابت
String name = "مطور Flutter";
int age = 25;
double salary = 5000.50;
bool isDeveloper = true;
// المصفوفات (Lists)
List colors = ["أحمر", "أخضر", "أزرق"];
colors.forEach((color) => print(color));
// الخرائط (Maps)
Map user = {
'name': 'أحمد',
'age': 30,
'email': 'ahmed@example.com',
'isActive': true,
};
// الدوال (Functions)
String greetUser(String userName) {
return "مرحباً $userName!";
}
// الدوال السهمية (Arrow Functions)
int add(int a, int b) => a + b;
// الفئات (Classes)
class User {
String name;
int age;
User(this.name, this.age);
void displayInfo() {
print("الاسم: $name, العمر: $age");
}
}
// الإنترفيسات (Interfaces) والـ Mixins
abstract class Animal {
void makeSound();
}
class Dog extends Animal {
@override
void makeSound() {
print("هاو هاو!");
}
}
// Future و Async/Await
Future fetchData() async {
try {
print("جاري جلب البيانات...");
await Future.delayed(Duration(seconds: 2));
print("تم جلب البيانات بنجاح!");
} catch (error) {
print("حدث خطأ: $error");
}
}
// اختبار الدوال
print(greetUser(name));
print("المجموع: ${add(10, 20)}");
User user1 = User("محمد", 28);
user1.displayInfo();
Dog dog = Dog();
dog.makeSound();
fetchData();
}
الخطوة 2: تعلم أساسيات Flutter
Flutter Basics هو فهم الأساسيات لتطوير التطبيقات مثل الواجهات، النصوص، والأزرار
الأهمية:
الأساس لفهم كيفية بناء تطبيق Flutter بسيط
الأدوات:
VS Code، Flutter SDK، Android Studio
مثال تطبيق Flutter أساسي:
// main.dart - التطبيق الرئيسي
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'تطبيق Flutter',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomeScreen(),
debugShowCheckedModeBanner: false,
);
}
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State {
int _counter = 0;
String _name = '';
bool _isDarkMode = false;
void _incrementCounter() {
setState(() {
_counter++;
});
}
void _resetCounter() {
setState(() {
_counter = 0;
});
}
void _toggleTheme() {
setState(() {
_isDarkMode = !_isDarkMode;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('أساسيات Flutter'),
centerTitle: true,
actions: [
IconButton(
icon: Icon(_isDarkMode ? Icons.light_mode : Icons.dark_mode),
onPressed: _toggleTheme,
),
],
),
body: SingleChildScrollView(
padding: EdgeInsets.all(20),
child: Column(
children: [
// صورة
Container(
height: 150,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.blue.withOpacity(0.1),
),
child: Center(
child: Icon(
Icons.flutter_dash,
size: 80,
color: Colors.blue,
),
),
),
SizedBox(height: 30),
// عنوان
Text(
'مرحباً بتطوير Flutter',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
textAlign: TextAlign.center,
),
SizedBox(height: 10),
// وصف
Text(
'Flutter هي منصة Google مفتوحة المصدر لبناء تطبيقات جميلة ومجمعة لنظامي Android و iOS من قاعدة كود واحدة',
style: TextStyle(
fontSize: 16,
color: Colors.grey[700],
height: 1.5,
),
textAlign: TextAlign.center,
),
SizedBox(height: 40),
// قسم العداد
Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
child: Padding(
padding: EdgeInsets.all(20),
child: Column(
children: [
Text(
'مثال العداد',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 15),
Text(
'$_counter',
style: TextStyle(
fontSize: 60,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: _incrementCounter,
style: ElevatedButton.styleFrom(
primary: Colors.blue,
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 15),
),
child: Text(
'زيادة',
style: TextStyle(fontSize: 16),
),
),
ElevatedButton(
onPressed: _resetCounter,
style: ElevatedButton.styleFrom(
primary: Colors.red,
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 15),
),
child: Text(
'إعادة تعيين',
style: TextStyle(fontSize: 16),
),
),
],
),
],
),
),
),
SizedBox(height: 30),
// قسم إدخال البيانات
Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
child: Padding(
padding: EdgeInsets.all(20),
child: Column(
children: [
Text(
'إدخال البيانات',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 15),
TextField(
decoration: InputDecoration(
labelText: 'أدخل اسمك',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
prefixIcon: Icon(Icons.person),
),
onChanged: (value) {
setState(() {
_name = value;
});
},
),
SizedBox(height: 15),
if (_name.isNotEmpty)
Container(
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Colors.green.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: Row(
children: [
Icon(Icons.check_circle, color: Colors.green),
SizedBox(width: 10),
Text(
'مرحباً $_name!',
style: TextStyle(
fontSize: 18,
color: Colors.green,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
),
),
SizedBox(height: 30),
// قسم الميزات
Text(
'ميزات Flutter',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 15),
Wrap(
spacing: 10,
runSpacing: 10,
children: [
FeatureChip(icon: Icons.code, text: 'كود واحد'),
FeatureChip(icon: Icons.speed, text: 'أداء عالي'),
FeatureChip(icon: Icons.brush, text: 'تصميم جميل'),
FeatureChip(icon: Icons.devices, text: 'متعدد المنصات'),
FeatureChip(icon: Icons.bug_report, text: 'تصحيح سهل'),
FeatureChip(icon: Icons.update, text: 'تحديث مباشر'),
],
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'زيادة العداد',
child: Icon(Icons.add),
backgroundColor: Colors.blue,
),
);
}
}
// مكون مخصص للرقائق
class FeatureChip extends StatelessWidget {
final IconData icon;
final String text;
FeatureChip({required this.icon, required this.text});
@override
Widget build(BuildContext context) {
return Chip(
avatar: Icon(icon, size: 18),
label: Text(text),
backgroundColor: Colors.blue.withOpacity(0.1),
);
}
}
الخطوة 3: تعلم إدارة الحالة
State Management هو إدارة حالة التطبيق مثل البيانات الديناميكية وطريقة العرض
الأهمية:
الأساس لفهم كيفية بناء تطبيقات معقدة ذات حالات متعددة
الأدوات:
Provider، Riverpod، Bloc
مثال State Management باستخدام Provider:
// 1. نموذج البيانات (Model)
import 'package:flutter/material.dart';
class User {
final String id;
final String name;
final String email;
User({
required this.id,
required this.name,
required this.email,
});
// تحويل إلى Map
Map toMap() {
return {
'id': id,
'name': name,
'email': email,
};
}
// إنشاء من Map
factory User.fromMap(Map map) {
return User(
id: map['id'],
name: map['name'],
email: map['email'],
);
}
}
// 2. State Management باستخدام Provider
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
// ChangeNotifier لإدارة الحالة
class UserProvider extends ChangeNotifier {
List _users = [];
bool _isLoading = false;
String _error = '';
List get users => _users;
bool get isLoading => _isLoading;
String get error => _error;
// إضافة مستخدم
Future addUser(String name, String email) async {
try {
_isLoading = true;
notifyListeners();
// محاكاة طلب API
await Future.delayed(Duration(seconds: 1));
final newUser = User(
id: DateTime.now().millisecondsSinceEpoch.toString(),
name: name,
email: email,
);
_users.add(newUser);
_error = '';
} catch (e) {
_error = 'حدث خطأ أثناء إضافة المستخدم: $e';
} finally {
_isLoading = false;
notifyListeners();
}
}
// حذف مستخدم
Future deleteUser(String userId) async {
try {
_isLoading = true;
notifyListeners();
// محاكاة طلب API
await Future.delayed(Duration(seconds: 1));
_users.removeWhere((user) => user.id == userId);
_error = '';
} catch (e) {
_error = 'حدث خطأ أثناء حذف المستخدم: $e';
} finally {
_isLoading = false;
notifyListeners();
}
}
// جلب المستخدمين
Future fetchUsers() async {
try {
_isLoading = true;
notifyListeners();
// محاكاة طلب API
await Future.delayed(Duration(seconds: 2));
// بيانات تجريبية
_users = [
User(id: '1', name: 'أحمد محمد', email: 'ahmed@example.com'),
User(id: '2', name: 'سارة خالد', email: 'sara@example.com'),
User(id: '3', name: 'محمد علي', email: 'mohamed@example.com'),
];
_error = '';
} catch (e) {
_error = 'حدث خطأ أثناء جلب البيانات: $e';
} finally {
_isLoading = false;
notifyListeners();
}
}
// تحديث مستخدم
Future updateUser(User updatedUser) async {
try {
_isLoading = true;
notifyListeners();
// محاكاة طلب API
await Future.delayed(Duration(seconds: 1));
final index = _users.indexWhere((user) => user.id == updatedUser.id);
if (index != -1) {
_users[index] = updatedUser;
}
_error = '';
} catch (e) {
_error = 'حدث خطأ أثناء تحديث المستخدم: $e';
} finally {
_isLoading = false;
notifyListeners();
}
}
}
// 3. الشاشة الرئيسية
class UserManagementScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final userProvider = Provider.of(context);
return Scaffold(
appBar: AppBar(
title: Text('إدارة المستخدمين'),
actions: [
IconButton(
icon: Icon(Icons.refresh),
onPressed: () => userProvider.fetchUsers(),
),
],
),
body: Column(
children: [
// نموذج إضافة مستخدم
AddUserForm(),
// عرض حالة التحميل
if (userProvider.isLoading)
LinearProgressIndicator(),
// عرض الأخطاء
if (userProvider.error.isNotEmpty)
Container(
padding: EdgeInsets.all(16),
margin: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.red),
),
child: Row(
children: [
Icon(Icons.error, color: Colors.red),
SizedBox(width: 10),
Expanded(
child: Text(
userProvider.error,
style: TextStyle(color: Colors.red),
),
),
],
),
),
// عرض المستخدمين
Expanded(
child: Consumer(
builder: (context, provider, child) {
if (provider.users.isEmpty && !provider.isLoading) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.people, size: 80, color: Colors.grey),
SizedBox(height: 20),
Text(
'لا يوجد مستخدمين',
style: TextStyle(
fontSize: 18,
color: Colors.grey,
),
),
SizedBox(height: 10),
TextButton(
onPressed: () => provider.fetchUsers(),
child: Text('جلب المستخدمين'),
),
],
),
);
}
return ListView.builder(
itemCount: provider.users.length,
itemBuilder: (context, index) {
final user = provider.users[index];
return UserCard(user: user);
},
);
},
),
),
],
),
);
}
}
// 4. نموذج إضافة مستخدم
class AddUserForm extends StatefulWidget {
@override
_AddUserFormState createState() => _AddUserFormState();
}
class _AddUserFormState extends State {
final _formKey = GlobalKey();
final _nameController = TextEditingController();
final _emailController = TextEditingController();
@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final userProvider = Provider.of(context, listen: false);
return Card(
margin: EdgeInsets.all(16),
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'إضافة مستخدم جديد',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16),
TextFormField(
controller: _nameController,
decoration: InputDecoration(
labelText: 'اسم المستخدم',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.person),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'يرجى إدخال الاسم';
}
return null;
},
),
SizedBox(height: 12),
TextFormField(
controller: _emailController,
decoration: InputDecoration(
labelText: 'البريد الإلكتروني',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.email),
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return 'يرجى إدخال البريد الإلكتروني';
}
if (!value.contains('@')) {
return 'البريد الإلكتروني غير صالح';
}
return null;
},
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () async {
if (_formKey.currentState!.validate()) {
await userProvider.addUser(
_nameController.text,
_emailController.text,
);
// مسح الحقول بعد الإضافة
_nameController.clear();
_emailController.clear();
// إخفاء لوحة المفاتيح
FocusScope.of(context).unfocus();
}
},
child: Text('إضافة مستخدم'),
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 16),
),
),
],
),
),
),
);
}
}
// 5. بطاقة عرض المستخدم
class UserCard extends StatelessWidget {
final User user;
UserCard({required this.user});
@override
Widget build(BuildContext context) {
final userProvider = Provider.of(context, listen: false);
return Card(
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue,
child: Text(
user.name[0].toUpperCase(),
style: TextStyle(color: Colors.white),
),
),
title: Text(
user.name,
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(user.email),
trailing: IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () => userProvider.deleteUser(user.id),
),
onTap: () {
// يمكن إضافة شاشة تفاصيل هنا
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('تفاصيل المستخدم'),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('الاسم: ${user.name}'),
SizedBox(height: 8),
Text('البريد الإلكتروني: ${user.email}'),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('إغلاق'),
),
],
),
);
},
),
);
}
}
// 6. تهيئة التطبيق
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => UserProvider()),
],
child: MaterialApp(
title: 'إدارة المستخدمين',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: UserManagementScreen(),
debugShowCheckedModeBanner: false,
),
),
);
}
الخطوة 4: تعلم التكامل مع Firebase
Firebase هي منصة شاملة توفر خدمات مثل التخزين السحابي، التوثيق والإشعارات
الأهمية:
الأساس لفهم كيفية إضافة ميزات خلفية إلى التطبيق دون الحاجة إلى بناء خادم مخصص
الأدوات:
Firebase Console
مثال Firebase Authentication:
// 1. تثبيت حزم Firebase
// في ملف pubspec.yaml
dependencies:
flutter:
sdk: flutter
firebase_core: ^2.15.0
firebase_auth: ^4.7.0
cloud_firestore: ^4.8.0
firebase_storage: ^11.2.0
google_sign_in: ^6.1.0
// 2. تهيئة Firebase
// lib/firebase_options.dart
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(MyApp());
}
// 3. Auth Service
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// تسجيل الدخول بالبريد الإلكتروني وكلمة المرور
Future signInWithEmail(String email, String password) async {
try {
UserCredential result = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
return result.user;
} catch (e) {
print("خطأ في تسجيل الدخول: $e");
return null;
}
}
// تسجيل مستخدم جديد
Future signUpWithEmail(String email, String password, String name) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
// تحديث معلومات الملف الشخصي
await result.user?.updateDisplayName(name);
return result.user;
} catch (e) {
print("خطأ في إنشاء الحساب: $e");
return null;
}
}
// تسجيل الدخول بـ Google
Future signInWithGoogle() async {
try {
final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
final GoogleSignInAuthentication? googleAuth =
await googleUser?.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
UserCredential result = await _auth.signInWithCredential(credential);
return result.user;
} catch (e) {
print("خطأ في تسجيل الدخول بـ Google: $e");
return null;
}
}
// تسجيل الخروج
Future signOut() async {
await _auth.signOut();
}
// الحصول على المستخدم الحالي
User? getCurrentUser() {
return _auth.currentUser;
}
// مراقبة حالة المصادقة
Stream get authStateChanges {
return _auth.authStateChanges();
}
// إعادة تعيين كلمة المرور
Future resetPassword(String email) async {
try {
await _auth.sendPasswordResetEmail(email: email);
} catch (e) {
print("خطأ في إعادة تعيين كلمة المرور: $e");
rethrow;
}
}
}
// 4. Firestore Service
import 'package:cloud_firestore/cloud_firestore.dart';
class FirestoreService {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
// جلب جميع المستخدمين
Stream> getUsers() {
return _firestore
.collection('users')
.snapshots()
.map((snapshot) => snapshot.docs
.map((doc) => UserData.fromFirestore(doc))
.toList());
}
// إضافة مستخدم جديد
Future addUser(UserData user) async {
await _firestore.collection('users').doc(user.id).set(user.toFirestore());
}
// تحديث مستخدم
Future updateUser(UserData user) async {
await _firestore.collection('users').doc(user.id).update(user.toFirestore());
}
// حذف مستخدم
Future deleteUser(String userId) async {
await _firestore.collection('users').doc(userId).delete();
}
// جلب مستخدم واحد
Future getUser(String userId) async {
DocumentSnapshot doc = await _firestore.collection('users').doc(userId).get();
if (doc.exists) {
return UserData.fromFirestore(doc);
}
return null;
}
}
// 5. نموذج بيانات المستخدم
class UserData {
final String id;
final String name;
final String email;
final String? phone;
final String? address;
final DateTime createdAt;
UserData({
required this.id,
required this.name,
required this.email,
this.phone,
this.address,
required this.createdAt,
});
// تحويل إلى Map لـ Firestore
Map toFirestore() {
return {
'id': id,
'name': name,
'email': email,
'phone': phone,
'address': address,
'createdAt': Timestamp.fromDate(createdAt),
};
}
// إنشاء من Firestore Document
factory UserData.fromFirestore(DocumentSnapshot doc) {
Map data = doc.data() as Map;
return UserData(
id: data['id'],
name: data['name'],
email: data['email'],
phone: data['phone'],
address: data['address'],
createdAt: (data['createdAt'] as Timestamp).toDate(),
);
}
}
// 6. شاشة تسجيل الدخول
class LoginScreen extends StatefulWidget {
@override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State {
final _formKey = GlobalKey();
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
final _authService = AuthService();
bool _isLoading = false;
@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
Future _signIn() async {
if (_formKey.currentState!.validate()) {
setState(() => _isLoading = true);
try {
final user = await _authService.signInWithEmail(
_emailController.text,
_passwordController.text,
);
if (user != null) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => HomeScreen()),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('فشل تسجيل الدخول')),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('حدث خطأ: $e')),
);
} finally {
setState(() => _isLoading = false);
}
}
}
Future _signInWithGoogle() async {
setState(() => _isLoading = true);
try {
final user = await _authService.signInWithGoogle();
if (user != null) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => HomeScreen()),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('فشل تسجيل الدخول بـ Google')),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('حدث خطأ: $e')),
);
} finally {
setState(() => _isLoading = false);
}
}
void _goToSignUp() {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => SignUpScreen()),
);
}
void _resetPassword() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('إعادة تعيين كلمة المرور'),
content: TextFormField(
controller: _emailController,
decoration: InputDecoration(
labelText: 'البريد الإلكتروني',
border: OutlineInputBorder(),
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('إلغاء'),
),
TextButton(
onPressed: () async {
try {
await _authService.resetPassword(_emailController.text);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('تم إرسال رابط إعادة التعيين')),
);
Navigator.pop(context);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('حدث خطأ: $e')),
);
}
},
child: Text('إرسال'),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
padding: EdgeInsets.all(20),
child: Column(
children: [
SizedBox(height: 60),
// الشعار
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(60),
),
child: Icon(
Icons.lock,
size: 60,
color: Colors.blue,
),
),
SizedBox(height: 40),
// عنوان الشاشة
Text(
'تسجيل الدخول',
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
SizedBox(height: 10),
Text(
'مرحباً بعودتك!',
style: TextStyle(
fontSize: 18,
color: Colors.grey,
),
),
SizedBox(height: 40),
// نموذج تسجيل الدخول
Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _emailController,
decoration: InputDecoration(
labelText: 'البريد الإلكتروني',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
prefixIcon: Icon(Icons.email),
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return 'يرجى إدخال البريد الإلكتروني';
}
if (!value.contains('@')) {
return 'البريد الإلكتروني غير صالح';
}
return null;
},
),
SizedBox(height: 20),
TextFormField(
controller: _passwordController,
decoration: InputDecoration(
labelText: 'كلمة المرور',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
prefixIcon: Icon(Icons.lock),
),
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'يرجى إدخال كلمة المرور';
}
if (value.length < 6) {
return 'كلمة المرور يجب أن تكون 6 أحرف على الأقل';
}
return null;
},
),
SizedBox(height: 10),
Align(
alignment: Alignment.centerLeft,
child: TextButton(
onPressed: _resetPassword,
child: Text('نسيت كلمة المرور؟'),
),
),
SizedBox(height: 20),
SizedBox(
width: double.infinity,
height: 56,
child: ElevatedButton(
onPressed: _isLoading ? null : _signIn,
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: _isLoading
? CircularProgressIndicator(color: Colors.white)
: Text(
'تسجيل الدخول',
style: TextStyle(fontSize: 18),
),
),
),
],
),
),
SizedBox(height: 30),
// أو تسجيل الدخول بـ Google
Text(
'أو',
style: TextStyle(color: Colors.grey),
),
SizedBox(height: 20),
OutlinedButton.icon(
onPressed: _isLoading ? null : _signInWithGoogle,
icon: Image.asset(
'assets/google.png',
width: 24,
height: 24,
),
label: Text('تسجيل الدخول بـ Google'),
style: OutlinedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 16, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
),
SizedBox(height: 40),
// رابط إنشاء حساب جديد
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('ليس لديك حساب؟'),
SizedBox(width: 5),
TextButton(
onPressed: _goToSignUp,
child: Text(
'إنشاء حساب جديد',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
],
),
],
),
),
);
}
}
الخطوة 5: تعلم الرسوم المتحركة المتقدمة
Advanced Animations هو إنشاء رسوم متحركة معقدة وديناميكية
الأهمية:
الأساس لفهم كيفية إضافة تفاعلات بصرية جذابة للتطبيق
الأدوات:
AnimatedBuilder، AnimationController، Rive/Flare
مثال الرسوم المتحركة المتقدمة:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'الرسوم المتحركة المتقدمة',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: AdvancedAnimationsScreen(),
debugShowCheckedModeBanner: false,
);
}
}
class AdvancedAnimationsScreen extends StatefulWidget {
@override
_AdvancedAnimationsScreenState createState() => _AdvancedAnimationsScreenState();
}
class _AdvancedAnimationsScreenState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation _sizeAnimation;
late Animation _rotationAnimation;
late Animation _colorAnimation;
late Animation _opacityAnimation;
late Animation _positionAnimation;
bool _isAnimating = false;
@override
void initState() {
super.initState();
// إنشاء AnimationController
_controller = AnimationController(
duration: Duration(milliseconds: 1500),
vsync: this,
);
// تكوين الرسوم المتحركة
_configureAnimations();
}
void _configureAnimations() {
// رسم متحرك للحجم
_sizeAnimation = Tween(
begin: 100.0,
end: 200.0,
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
),
);
// رسم متحرك للدوران
_rotationAnimation = Tween(
begin: 0.0,
end: 2 * 3.14159, // 360 درجة بالراديان
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
),
);
// رسم متحرك للألوان
_colorAnimation = ColorTween(
begin: Colors.blue,
end: Colors.purple,
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
),
);
// رسم متحرك للشفافية
_opacityAnimation = Tween(
begin: 0.3,
end: 1.0,
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
),
);
// رسم متحرك للموضع
_positionAnimation = Tween(
begin: Offset(0, 0),
end: Offset(0, -0.5),
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
),
);
// إضافة مستمع لتغيير الحالة
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
setState(() {
_isAnimating = false;
});
} else if (status == AnimationStatus.dismissed) {
setState(() {
_isAnimating = false;
});
}
});
}
void _toggleAnimation() {
setState(() {
_isAnimating = true;
});
if (_controller.status == AnimationStatus.completed) {
_controller.reverse();
} else {
_controller.forward();
}
}
void _resetAnimation() {
_controller.reset();
setState(() {
_isAnimating = false;
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('الرسوم المتحركة المتقدمة'),
),
body: SingleChildScrollView(
padding: EdgeInsets.all(20),
child: Column(
children: [
// رسم متحرك مركب باستخدام AnimatedBuilder
Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Container(
padding: EdgeInsets.all(20),
child: Column(
children: [
Text(
'رسم متحرك مركب',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 20),
AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Transform.translate(
offset: _positionAnimation.value,
child: Transform.rotate(
angle: _rotationAnimation.value,
child: Container(
width: _sizeAnimation.value,
height: _sizeAnimation.value,
decoration: BoxDecoration(
color: _colorAnimation.value,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 10,
offset: Offset(0, 5),
),
],
),
child: Center(
child: Opacity(
opacity: _opacityAnimation.value,
child: Icon(
Icons.flutter_dash,
size: 60,
color: Colors.white,
),
),
),
),
),
);
},
),
SizedBox(height: 30),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: _toggleAnimation,
style: ElevatedButton.styleFrom(
primary: _isAnimating ? Colors.orange : Colors.blue,
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 15),
),
child: Text(
_isAnimating ? 'إيقاف' : 'تشغيل',
style: TextStyle(fontSize: 16),
),
),
ElevatedButton(
onPressed: _resetAnimation,
style: ElevatedButton.styleFrom(
primary: Colors.red,
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 15),
),
child: Text(
'إعادة تعيين',
style: TextStyle(fontSize: 16),
),
),
],
),
SizedBox(height: 20),
LinearProgressIndicator(
value: _controller.value,
backgroundColor: Colors.grey[300],
valueColor: AlwaysStoppedAnimation(Colors.blue),
),
SizedBox(height: 10),
Text(
'التقدم: ${(_controller.value * 100).toStringAsFixed(1)}%',
style: TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
],
),
),
),
SizedBox(height: 30),
// رسم متحرك نصي
Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Container(
padding: EdgeInsets.all(20),
child: Column(
children: [
Text(
'رسم متحرك نصي',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 20),
AnimatedText(),
],
),
),
),
SizedBox(height: 30),
// رسم متحرك موجة
Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Container(
padding: EdgeInsets.all(20),
child: Column(
children: [
Text(
'رسم متحرك موجة',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 20),
WaveAnimation(),
],
),
),
),
SizedBox(height: 30),
// رسم متحرك تحميل
Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Container(
padding: EdgeInsets.all(20),
child: Column(
children: [
Text(
'رسم متحرك تحميل',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 20),
LoadingAnimation(),
],
),
),
),
SizedBox(height: 30),
// رسم متحرك انتقال
Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Container(
padding: EdgeInsets.all(20),
child: Column(
children: [
Text(
'رسم متحرك انتقال',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 20),
HeroAnimation(),
],
),
),
),
],
),
),
);
}
}
// رسم متحرك نصي
class AnimatedText extends StatefulWidget {
@override
_AnimatedTextState createState() => _AnimatedTextState();
}
class _AnimatedTextState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation _fadeAnimation;
late Animation _scaleAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
_fadeAnimation = Tween(
begin: 0.3,
end: 1.0,
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
),
);
_scaleAnimation = Tween(
begin: 0.8,
end: 1.2,
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Transform.scale(
scale: _scaleAnimation.value,
child: Opacity(
opacity: _fadeAnimation.value,
child: Text(
'Flutter Animations',
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.blue,
shadows: [
Shadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 10,
offset: Offset(2, 2),
),
],
),
),
),
);
},
);
}
}
// رسم متحرك موجة
class WaveAnimation extends StatefulWidget {
@override
_WaveAnimationState createState() => _WaveAnimationState();
}
class _WaveAnimationState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(seconds: 4),
vsync: this,
)..repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
height: 100,
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return CustomPaint(
painter: WavePainter(_controller.value),
size: Size(double.infinity, 100),
);
},
),
);
}
}
class WavePainter extends CustomPainter {
final double value;
WavePainter(this.value);
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill
..strokeWidth = 2.0;
final path = Path();
path.moveTo(0, size.height / 2);
for (double i = 0; i <= size.width; i++) {
final y = size.height / 2 +
sin((i / size.width * 4 * 3.14159) + value * 2 * 3.14159) * 30;
path.lineTo(i, y);
}
path.lineTo(size.width, size.height);
path.lineTo(0, size.height);
path.close();
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(covariant WavePainter oldDelegate) {
return oldDelegate.value != value;
}
}
// رسم متحرك تحميل
class LoadingAnimation extends StatefulWidget {
@override
_LoadingAnimationState createState() => _LoadingAnimationState();
}
class _LoadingAnimationState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(seconds: 1),
vsync: this,
)..repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
height: 100,
child: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Transform.rotate(
angle: _controller.value * 2 * 3.14159,
child: Icon(
Icons.refresh,
size: 60,
color: Colors.blue,
),
);
},
),
),
);
}
}
// رسم متحرك انتقال
class HeroAnimation extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
height: 200,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Hero(
tag: 'logo',
child: Icon(
Icons.flutter_dash,
size: 80,
color: Colors.blue,
),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HeroDetailScreen(),
),
);
},
child: Text('عرض التفاصيل'),
),
],
),
),
);
}
}
class HeroDetailScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('تفاصيل الرسم المتحرك'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Hero(
tag: 'logo',
child: Icon(
Icons.flutter_dash,
size: 200,
color: Colors.blue,
),
),
SizedBox(height: 30),
Text(
'رسم متحرك انتقال Hero',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 10),
Text(
'هذا مثال على استخدام Hero Animation\nلإنشاء انتقالات سلسة بين الشاشات',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: Colors.grey,
),
),
SizedBox(height: 30),
ElevatedButton(
onPressed: () => Navigator.pop(context),
child: Text('رجوع'),
),
],
),
),
);
}
}
// دالة الجيب (Sine) للرسم
double sin(double x) => (x - x * x * x / 6 + x * x * x * x * x / 120);
هندسة تطبيقات Flutter
Dart Code
مكونات Flutter، منطق التطبيق
Flutter Engine
Skia Graphics، Dart VM، Platform Channels
Native Platform
Android (Java/Kotlin)، iOS (Swift/Objective-C)
أدوات تطوير Flutter
VS Code
محرر نصوص خفيف مع دعم ممتاز لـ Flutter
Android Studio
بيئة تطوير متكاملة مع أدوات متقدمة
Flutter DevTools
أدوات تصحيح وتحليل متكاملة
المزايا والتحديات
المزايا
- طلب عالي: هناك طلب كبير على مطوري Flutter خاصة في الشركات الناشئة والشركات الصغيرة
- أدوات مجانية: معظم الأدوات المستخدمة مثل Flutter SDK و Firebase مجانية أو تقدم خطط مجانية
- تأثير إيجابي: يمكنك المساهمة في تحسين تجربة المستخدم عبر الإنترنت
- إبداع لا محدود: يمكنك تصميم تطبيقات مبتكرة تعمل على Android و iOS بكود واحد
- Hot Reload: تحديث التطبيق مباشرة دون إعادة تشغيل
التحديات
- منحنى التعلم الحاد: يتطلب فهماً جيداً للغات البرمجة، التصميم وأساسيات Flutter
- تعقيد الأنظمة: قد تواجه تحديات في إدارة التطبيقات الكبيرة أو المعقدة
- تحديثات متكررة: الأدوات والمعايير تتطور باستمرار، مما يتطلب تحديث المعرفة بشكل منتظم
- حجم التطبيق: قد يكون حجم التطبيق النهائي أكبر من التطبيقات الأصلية
أنواع مشاريع Flutter
تطبيقات التجارة الإلكترونية
متاجر إلكترونية كاملة مع دفع وتتبع طلبات
تطبيقات الوسائط
بث فيديو، موسيقى، ومحتوى تعليمي
تطبيقات الأعمال
إدارة، تحليلات، وتقارير للمؤسسات
الخلاصة
Flutter يوفر حلاً ممتازاً لتطوير تطبيقات جميلة وسريعة تعمل على منصات متعددة باستخدام كود Dart واحد. من خلال إتقان Dart، فهم Widgets، وإتقان State Management، يمكنك بناء تطبيقات احترافية متعددة المنصات.
نصائح للبدء:
- ابدأ بتعلم Dart جيداً قبل Flutter
- تمرن على Widgets الأساسية أولاً
- استخدم Provider لإدارة الحالة البسيطة
- تعلم Firebase للخدمات الخلفية السريعة
- ابنِ مشروع عملي يوضح مهاراتك