ماذا سنتعلم؟ في هذا الدرس، سنتعلم كيفية إضافة النصوص والصور (Assets) إلى تطبيق Flutter الخاص بنا وتنسيقها باحترافية لتحسين تجربة المستخدم وجمالية التطبيق.
تُعد النصوص والصور من العناصر الأساسية في أي تطبيق، وفهم كيفية إدارتها وتنسيقها بشكل صحيح أمر بالغ الأهمية لإنشاء واجهات مستخدم جذابة وفعالة.
الخطوة الأولى: إعداد الأصول (Assets) في مشروع Flutter
قبل استخدام أي صور أو خطوط مخصصة، يجب إضافتها إلى مشروعك وتحديد مسارها في ملف pubspec.yaml.
1. قم بإنشاء مجلد جديد باسم assets في الجذر الرئيسي لمشروعك (بجانب lib و pubspec.yaml).
2. ضع صورك (مثل my_image.png) داخل هذا المجلد.
3. افتح ملف pubspec.yaml وأضف مسار الأصول تحت قسم flutter. تأكد من الحفاظ على المسافات البادئة الصحيحة:
flutter:
uses-material-design: true
# لتضمين الأصول مثل الصور
assets:
- assets/my_image.png
- assets/another_image.jpg # يمكنك إضافة صور أخرى هنا
# لتضمين الخطوط المخصصة (اختياري)
# fonts:
# - family: MyCustomFont
# fonts:
# - asset: assets/fonts/MyCustomFont-Regular.ttf
# - asset: assets/fonts/MyCustomFont-Bold.ttf
# weight: 700
تذكر دائماً تشغيلflutter pub getبعد تعديل ملفpubspec.yamlلتحديث تبعيات المشروع وضمان التعرف على الأصول الجديدة.
الخطوة الثانية: عرض النصوص وتنسيقها باحترافية
نستخدم الـ Text Widget لعرض النصوص، ويمكن تنسيقه باستخدام الـ TextStyle Widget الذي يوفر مجموعة واسعة من الخصائص.
import 'package:flutter/material.dart';
class StyledTextWidget extends StatelessWidget {
const StyledTextWidget({super.key});
@override
Widget build(BuildContext context) {
return Text(
'مرحباً بكم في عالم Flutter المذهل!', // النص المراد عرضه
textAlign: TextAlign.center, // محاذاة النص في المنتصف
style: TextStyle(
fontSize: 24, // حجم الخط
color: Colors.deepPurple, // لون الخط
fontWeight: FontWeight.bold, // وزن الخط (عريض)
fontStyle: FontStyle.italic, // نمط الخط (مائل)
letterSpacing: 1.2, // المسافة بين الحروف
wordSpacing: 2.0, // المسافة بين الكلمات
shadows: [ // إضافة ظل للنص
Shadow(
blurRadius: 4.0, // نصف قطر التمويه للظل
color: Colors.black.withOpacity(0.3), // لون الظل مع شفافية
offset: const Offset(2.0, 2.0), // إزاحة الظل (س، ص)
),
],
decoration: TextDecoration.underline, // إضافة خط تحت النص
decorationColor: Colors.amber, // لون الخط السفلي
decorationStyle: TextDecorationStyle.wavy, // نمط الخط السفلي (مموج)
),
);
}
}
الخطوة الثالثة: عرض الصور وتنسيقها باحترافية
لعرض الصور التي أضفناها كأصول، نستخدم الـ Image.asset Widget. يمكننا التحكم في حجمها، كيفية ملاءمتها للمساحة المتاحة، وحتى إضافة تأثيرات بصرية.
import 'package:flutter/material.dart';
class StyledImageWidget extends StatelessWidget {
const StyledImageWidget({super.key});
@override
Widget build(BuildContext context) {
return Container(
width: 200, // تحديد عرض الحاوية للصورة
height: 200, // تحديد ارتفاع الحاوية للصورة
decoration: BoxDecoration(
color: Colors.grey[200], // لون خلفية الحاوية
borderRadius: BorderRadius.circular(20), // حواف دائرية للحاوية
border: Border.all(color: Colors.deepPurple, width: 3), // حدود للحاوية
boxShadow: [ // إضافة ظل للحاوية
BoxShadow(
color: Colors.black.withOpacity(0.2), // لون الظل مع شفافية
spreadRadius: 5, // انتشار الظل
blurRadius: 7, // تمويه الظل
offset: const Offset(0, 3), // إزاحة الظل (س، ص)
),
],
),
child: ClipRRect( // لقص الصورة داخل الحاوية ذات الحواف الدائرية
borderRadius: BorderRadius.circular(17), // حواف دائرية للصورة (أقل قليلاً من الحاوية)
child: Image.asset(
'assets/my_image.png', // مسار الصورة من مجلد الأصول
fit: BoxFit.cover, // كيفية ملء الصورة للمساحة المتاحة (تغطية مع الحفاظ على الأبعاد)
alignment: Alignment.center, // محاذاة الصورة داخل الحاوية
semanticLabel: 'صورة توضيحية لتطبيق Flutter', // وصف للصورة لأغراض الوصولية
// color: Colors.blue.withOpacity(0.5), // تطبيق لون على الصورة
// colorBlendMode: BlendMode.colorBurn, // نمط دمج اللون مع الصورة
),
),
);
}
}
الخطوة الرابعة: دمج النصوص والصور في واجهة مستخدم متكاملة
لإنشاء واجهة مستخدم متكاملة، سنقوم بدمج النصوص والصور باستخدام Widgets مثل Column أو Row، مع إضافة بعض التباعد والتنسيقات.
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(
title: 'Flutter Assets & Styling',
theme: ThemeData(
primarySwatch: Colors.deepPurple,
fontFamily: 'Roboto', // يمكنك تحديد خط افتراضي للتطبيق بأكمله
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('الأصول والتنسيق في Flutter'),
centerTitle: true, // توسيط عنوان الـ AppBar
),
body: Center(
child: SingleChildScrollView( // يسمح بالتمرير إذا كان المحتوى أكبر من الشاشة
padding: const EdgeInsets.all(20.0), // هوامش داخلية حول المحتوى
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // محاذاة العناصر في المنتصف عمودياً
crossAxisAlignment: CrossAxisAlignment.center, // محاذاة العناصر في المنتصف أفقياً
children: <Widget>[
// نص عنوان مع تنسيق خاص
Text(
'دليل Flutter الاحترافي',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.w900, // خط سميك جداً
color: Colors.deepPurple[700],
letterSpacing: 1.5,
shadows: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 3,
offset: const Offset(1, 1),
),
],
),
),
const SizedBox(height: 20), // مسافة فارغة عمودية
// نص وصفي مع تنسيق
Text(
'تعلم كيفية إضافة وتنسيق النصوص والصور لإنشاء واجهات مستخدم جذابة وفعالة.',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: Colors.grey[700],
height: 1.5, // ارتفاع السطر
),
),
const SizedBox(height: 30), // مسافة فارغة عمودية
// حاوية الصورة مع التنسيقات المتقدمة
Container(
width: MediaQuery.of(context).size.width * 0.8, // عرض 80% من عرض الشاشة
height: 250, // ارتفاع ثابت
decoration: BoxDecoration(
color: Colors.white, // خلفية بيضاء للحاوية
borderRadius: BorderRadius.circular(15), // حواف دائرية
boxShadow: [
BoxShadow(
color: Colors.deepPurple.withOpacity(0.2),
spreadRadius: 5,
blurRadius: 10,
offset: const Offset(0, 5),
),
],
gradient: LinearGradient( // تدرج لوني كخلفية
colors: [Colors.deepPurple.shade50, Colors.deepPurple.shade100],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(15), // حواف دائرية للصورة
child: Image.asset(
'assets/my_image.png', // تأكد من وجود هذه الصورة في مجلد assets
fit: BoxFit.cover, // ملء المساحة مع الحفاظ على الأبعاد
errorBuilder: (context, error, stackTrace) { // معالج الأخطاء في حال عدم تحميل الصورة
return const Center(
child: Icon(
Icons.broken_image,
size: 50,
color: Colors.red,
),
);
},
),
),
),
const SizedBox(height: 30), // مسافة فارغة عمودية
// زر تفاعلي
ElevatedButton.icon(
onPressed: () {
// إضافة منطق عند الضغط على الزر هنا
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('تم النقر على الزر!'))
);
},
icon: const Icon(Icons.star),
label: const Text('اكتشف المزيد'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple, // لون خلفية الزر
foregroundColor: Colors.white, // لون نص وأيقونة الزر
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 15), // حشوة داخلية للزر
textStyle: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder( // شكل الزر
borderRadius: BorderRadius.circular(10), // حواف دائرية للزر
),
),
),
],
),
),
),
);
}
}
الكود النهائي الكامل
هذا هو الكود الكامل الذي يجمع جميع الخطوات ويشكل تطبيق Flutter وظيفي.
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(
title: 'Flutter Assets & Styling',
theme: ThemeData(
primarySwatch: Colors.deepPurple,
fontFamily: 'Roboto', // يمكنك تحديد خط افتراضي للتطبيق بأكمله
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('الأصول والتنسيق في Flutter'),
centerTitle: true, // توسيط عنوان الـ AppBar
),
body: Center(
child: SingleChildScrollView( // يسمح بالتمرير إذا كان المحتوى أكبر من الشاشة
padding: const EdgeInsets.all(20.0), // هوامش داخلية حول المحتوى
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // محاذاة العناصر في المنتصف عمودياً
crossAxisAlignment: CrossAxisAlignment.center, // محاذاة العناصر في المنتصف أفقياً
children: <Widget>[
// نص عنوان مع تنسيق خاص
Text(
'دليل Flutter الاحترافي',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.w900, // خط سميك جداً
color: Colors.deepPurple[700],
letterSpacing: 1.5,
shadows: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 3,
offset: const Offset(1, 1),
),
],
),
),
const SizedBox(height: 20), // مسافة فارغة عمودية
// نص وصفي مع تنسيق
Text(
'تعلم كيفية إضافة وتنسيق النصوص والصور لإنشاء واجهات مستخدم جذابة وفعالة.',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: Colors.grey[700],
height: 1.5, // ارتفاع السطر
),
),
const SizedBox(height: 30), // مسافة فارغة عمودية
// حاوية الصورة مع التنسيقات المتقدمة
Container(
width: MediaQuery.of(context).size.width * 0.8, // عرض 80% من عرض الشاشة
height: 250, // ارتفاع ثابت
decoration: BoxDecoration(
color: Colors.white, // خلفية بيضاء للحاوية
borderRadius: BorderRadius.circular(15), // حواف دائرية
boxShadow: [
BoxShadow(
color: Colors.deepPurple.withOpacity(0.2),
spreadRadius: 5,
blurRadius: 10,
offset: const Offset(0, 5),
),
],
gradient: LinearGradient( // تدرج لوني كخلفية
colors: [Colors.deepPurple.shade50, Colors.deepPurple.shade100],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(15), // حواف دائرية للصورة
child: Image.asset(
'assets/my_image.png', // تأكد من وجود هذه الصورة في مجلد assets
fit: BoxFit.cover, // ملء المساحة مع الحفاظ على الأبعاد
errorBuilder: (context, error, stackTrace) { // معالج الأخطاء في حال عدم تحميل الصورة
return const Center(
child: Icon(
Icons.broken_image,
size: 50,
color: Colors.red,
),
);
},
),
),
),
const SizedBox(height: 30), // مسافة فارغة عمودية
// زر تفاعلي
ElevatedButton.icon(
onPressed: () {
// إضافة منطق عند الضغط على الزر هنا
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('تم النقر على الزر!'))
);
},
icon: const Icon(Icons.star),
label: const Text('اكتشف المزيد'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple, // لون خلفية الزر
foregroundColor: Colors.white, // لون نص وأيقونة الزر
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 15), // حشوة داخلية للزر
textStyle: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder( // شكل الزر
borderRadius: BorderRadius.circular(10), // حواف دائرية للزر
),
),
),
],
),
),
),
);
}
}
النتيجة المتوقعة
عند تشغيل التطبيق، ستشاهد شاشة تحتوي على شريط علوي (AppBar) بعنوان "الأصول والتنسيق في Flutter". في جسم التطبيق، ستجد:
- عنوان رئيسي كبير وسميك "دليل Flutter الاحترافي" بلون بنفسجي داكن.
- نص وصفي أسفله يشرح محتوى الدرس بلون رمادي.
- صورة
my_image.png(التي أضفتها إلى مجلدassets) معروضة داخل حاوية ذات حواف دائرية، ظل، وتدرج لوني كخلفية. الصورة ستكون بحجم يغطي 80% من عرض الشاشة وارتفاع ثابت 250 بكسل. - زر "اكتشف المزيد" الأنيق ذو أيقونة نجمة بلون بنفسجي مع حواف دائرية.
هذا التصميم يوضح كيفية دمج النصوص والصور وتطبيق تنسيقات متقدمة لإنشاء واجهة مستخدم احترافية وجذابة في تطبيقات Flutter.