You are on page 1of 51

1

lowercase with( ‫اسم المشروع ال يحتوي على مسافات وال أحرف كبيرة ويمكن أن يحتوي على‬
)underscores
:‫أنواع المتغيرات الرقمية‬
int , double , num
int , double ‫ عبارة عن األب لكل من‬num
:Example
;int x = 5
double y = 7.2; ً‫يقبل أرقام صحيحة أيضا‬
;num number1 = 5
print(number1.runtimeType); int ‫لطباعة نوع المتغير وهنا هو‬
;num number2 = 2.2
print(number2.runtimeType); double ‫لطباعة نوع المتغير وهنا هو‬
String ‫المتغير النصي هو‬
:Example
String name = "Noor";
print(name.length); ‫اليجاد\ طول النص‬
print(name.toLowerCase()); ‫لتحويل النص ألحرف صغيرة‬
print(name.toUpperCase()); ‫لتحويل النص ألحرف كبيرة‬

bool ‫ ) هو‬true or false ( ‫المتغير المنطقي‬


;bool isMarried = false
;isMarried = true
‫‪2‬‬

‫هناك نوعان اخران من المتغيرات وهما ‪ dynamic‬و ‪:var‬‬


‫أوالً‪ :dynamic :‬يقبل جميع القيم ( أرقام صحيحة\ أرقام عشرية ونصوص) ويمكن التغيير بينهما‬
‫كما نشاء‬
‫‪:Example‬‬
‫;"‪dynamic x = "Noor‬‬
‫;‪name = 5‬‬ ‫هنا غيرنا قيمة المتغير إلى ‪5‬‬
‫;‪name = 3.2‬‬ ‫هنا غيرنا قيمة المتغير مرة أخرى إلى ‪3.2‬‬

‫‪ $‬عندما\ نريد\ طباعة\ متغير مع نص نستخدم عالمة‬


‫;"(‪print("your name is $name‬‬
‫;"( ‪print("number of charcters is ${name.lenght‬‬

‫ثانياً‪ :var \:‬يقبل جميع القيم ( أرقام صحيحة أرقام عشرية ونصوص) للمرة األولى فقط عند‬
‫التعريف وال يمكن تغيير النوع مرة اخرى ولكن يمكن تغيير القيمة‬
‫‪:Example‬‬
‫;"‪var x = "Noor‬‬
‫;‪x = 5‬‬ ‫يمكن تغيير القيمة فقط) ) هكذا خطأ ألن المتغير تم تعريفه كنص وال يمكن تغييره‬
‫لرقم‬
‫هكذا صحيح ألننا غيرنا القيمة من نص الى نص اخر ;"‪x = "ahmed‬‬

‫باختصار ال‪ var‬عند تعريفه ألول مرة يمكن وضع ما نشاء فيه ( نصوص أو أرقام أو أرقام عشرية)‬
‫ولكن بعد ذلك ال يمكننا تغيير النوع بمعنى اذا كنا عرفنا المتغير كرقم ال يمكن تحويله لنص واذا‬
‫كان نص ال يمكن تحويله لرقم‬
‫المسموح فقط تغيير القمية بمعنى يمكن تغيير القيم من نص لنص اخر أو من رقم لرقم اخر‬
3

: if ‫دالة‬
int number = 12;
if (number % 2 == 0) {
print("Even");
} else {
print("Odd");
}
‫ كما نالحظ ال يوجد تغيير عليها نفس لغات البرمجة\ األخرى‬if‫دالة ال‬

bool x = 7 > 5 ? true : false; short if or ternary operator ‫تسمى‬


false ‫ واذا كان غير متحقق‬true ‫ هي‬x ‫ ) تكون قيمة‬7 )5 > ‫اذا كان الشرط متحقق‬

:for loop
\:‫الطريقة األولى وهي المعتادة‬
for (var i = 0; i < 5; i++) {
    print("Hello world");
}

\:‫الطريقة الثانية‬
;List<int> numbers = [ 1 , 2 , 3 , 4 , 5]
for (int num in numbers) {
    print(num);
}
:foreach ‫الطريقة الثالثة وهي‬
{ numbers.forEach((element)
;print(element)    
;)}  
‫‪4‬‬

‫‪Null saftey in dart:‬‬


‫اما نعطيه قيمة افتراضية أو نضع عالمة االستفهام ;‪String? name‬‬
‫هذا يسمى ‪String‬وال يقبل ‪ null‬يظهر ايرور ‪String:‬‬
‫هذا يسمى ‪nullable String‬بمعنى أنه يقبل ‪String?: null‬‬
‫;‪int? x‬‬
‫هكذا ايرور ألن قيمة‪ x‬هي ‪int y = x; null‬‬
‫;‪int y = x ?? 0‬‬
‫معناها أنه اذا كان ل ‪ x‬قيمة نخزنها في ‪ y‬واذا لم يكن لها قيمة نجعل قيمة ‪ y‬صفر‬

‫هنا اذا كان ل ‪x‬قيمة تبقى كما هي أما اذا كانت ‪ null‬نجعل قيمتها ‪x ??= 8; 8‬‬

‫‪Lists in dart:‬‬
‫;]‪List list = [true , "noor " , 5 , 3.2 , false‬‬
‫;]‪List<dynamic> list = [true , "noor " , 5 , 3.2‬‬
‫ما بين األقواس <‪ >dynamic‬يسمى ‪generic type‬‬
‫الحالتان نفس المعنى سواء وضعنا ‪ dynamic‬أم لم نضع كالهما نفس الحالة\‬
‫لست تقبل جميع القيم بشكل افتراضي تكون من نوع ‪dynamic‬‬

‫لست من نوع سترنج ;]" ‪List<String> list = ["noor " , "ahmed " , "abood‬‬
‫لست من نوع أرقام صحيحة ;]‪List<int> list = [27 , 1 , 2003‬‬
‫لست من نوع أرقام عشرية ;]‪List<double> list = [1.3 , 2.4 ,7.9‬‬

‫مالحظة‪ :‬اللست تقبل التكرار‬


‫;]‪List<int> list = [27 , 1 , 2003, 1 , 27‬‬
‫‪5‬‬

‫لكي ندمج ‪ lists 2‬نقوم بالتالي‪:‬‬


‫;]" ‪List<String> list1 = ["noor " , "ahmed " , "abood‬‬
‫;]"‪List<String> list2 = ["belal " , "yaser " , "mohammed‬‬
‫هنا ال يحدث أي خطأ ألن الليست األولى والثانية\ ;]‪List<String> allLists = [...list1 , ...list2‬‬
‫لديهما قيم‬
‫;‪List <String> list3‬‬
‫;]‪List<String> allLists = [...list1 , ...list2 , ...list3‬‬
‫هنا يحدث ايرور ألن ‪ list3‬قيمتها ‪null‬‬

‫;][ = ‪List3 <String> list3‬‬


‫;]‪List<String> allLists = [...list1 , ...list2 , ...list3‬‬
‫هنا ال يحدث ايرور ألن ‪ list1 , list2‬لديهما قيم و ‪ list3‬عبارة عن ليست فارغة‬
‫مالحظة‪ :‬الفرق بين هذه الحالة\ والحالة\ السابقة أن الحالة التانية كانت الليست قيمتها ‪ null‬أما‬
‫في هذه الحالة فهي ليست فارغة (هناك فرق بين ‪ null‬والفارغ)‬

‫بمعنى جلب عناصر ‪list1‬وتخزينها في الليست الجديدة ‪...list1:‬‬


‫بمعنى جلب عناصر ‪list2‬وتخزينها في الليست الجديدة ‪...list2:‬‬
‫‪ ...‬يسمى ‪spread operator‬‬

‫‪:‬بعض دوال اللست‬


‫;]"‪List elements = [1 , 4.2 , true , "noor‬‬

‫اضافة عنصر اخر الليست ;)"‪elements.add("ahmed‬‬

‫اضافة عنصر في مكان محدد ;)"‪elements.insert(1 , "nader‬‬


‫‪6‬‬

‫;]"‪print(element); -> [1 , "nader" , 4.2 , true , "noor ", "ahmed‬‬


‫‪( 6‬ألننا قمنا باضافة\ عنصرين\ اضافيين) >‪) -‬اليجاد\ عدد عناصر اللست( ‪elements.length‬‬
‫‪) -> false‬لفحص اذا كانت فارغة أم ال( ‪elements.isEmpty‬‬

‫‪) -> true‬لفحص اذا كانت تحتوي على عناصر أم ال( ‪elements.isNotEmpty‬‬

‫‪) -> ("ahmed" , "noor" , true , 4.2 ,‬لطباعتها بشكل معكوس( ‪elements.reversed‬‬
‫;)‪"nader" , 1‬‬
‫ال تؤثر على اللست األصلية وإنما مجرد طباعة ( تبقى اللست األصلية كما هي (بس طباعة))‬

‫‪elements.first -> 1‬‬

‫"‪elements.last -> "noor‬‬

‫اذا أردنا أن حول من ‪ list String‬إلى ‪ list int‬مثال لدينا ‪ list‬بها مجموعة\ اسماء ونريد أن نستخدمها\‬
‫لعمل ليست أخرى تحتوي على عدد أحرف كل اسم من االسماء نستخدم دالة ‪( map‬دالة‬
‫‪ map‬وليست ‪ )Map‬هي دالة وليس نوع تخزين‬

‫;]" ‪List<String> names = ["noor " , "ahmed " , "abood‬‬


‫{ )‪  List <int> namesLengths = names.map( (e‬‬
‫;‪  return e.length‬‬
‫;)(‪}).toList‬‬

‫الفرق بين دالة الماب و ‪ foreach‬أن ال‪ foreach‬ال ترجع داتا أما الماب بترجع داتا من نوع ‪Itreable‬‬
‫عبارة عن األب لكل داتا قابلة لعمل ‪ loop‬عليها مثل ‪Itreable:Map , List‬‬

‫;)(‪names.where( (e) => e == "ahmed").toList‬‬


‫لعمل فلتر على االسماء بترجع النا جميع االسماء التي قيمتها ‪ahmed‬‬
‫‪7‬‬

‫‪-‬بترجع موقع العنصر اذا لم يكن موجود\ بترجع ‪Names.indexOf("ahmed"); 1‬‬

‫لترتيب عناصر ال‪: list‬‬


‫هذه ترتب عناصر الليست االصلية ;)(‪names.sort‬‬

‫مالحظة‪ :‬هنا فرق بين دالة ‪ reverse‬ودالة ‪sort‬‬


‫تقوم بطباعة العناصر بشكل معكوس وال تقوم بعكس الليست األصلية ‪reverse:‬‬
‫تقوم بترتيب عناصر الليست األصلية ‪sort:‬‬

‫‪Sets in dart:‬‬
‫ال‪ set‬في دارت ال تقبل التكرار ولكن ال يحدث ايرور عند التكرار ولكن يتم تجاهل العنصر المكرر‬
‫كأنه غير موجود‬

‫}‪;Set numbers = {1 , 5 , 5 , 7‬‬


‫نالحظ أنه تم تجاهل العنصر المكرر }‪print(numbers); -> { 1 , 5 , 7‬‬
‫نالحظ أنه تم تجاهل العنصر المكرر ‪print(numbers.lenght); -> 3‬‬

‫أقواس اللست []‬


‫أقواس ال‪}{ set‬‬
‫مالحظة‪ :‬ما ينطبق على ‪ List‬من دوال ينطبق على ‪Set‬‬
‫‪:Maps in dart‬‬
‫‪{ = Map<String , dynamic> data‬‬
‫"‪,"name": "ahmed‬‬
‫"‪,age": 23‬‬
‫‪isMale: true‬‬
‫};‬
8

‫ من نوع سترنج‬key‫ وعادة ما يكون ال‬value‫ وال‬key‫الماب تعتمد مبدأ ال‬


‫ ال يحدث ايرور وانما يتم تعديل القيمة الخاص به‬key ‫اذا تم تكرار‬
{ = Map<String , dynamic> data
,"name": "ahmed"
"name": "mohammed", ‫هكذا تم تغيير القيمة‬
,age": 23"
"true"isMale :
;}

foreach ‫لطباعة الماب نستخدم‬


{ data.forEach((key, value)
;print('the key is $key, and the value is $value')    
;)}  

: Map‫بعض دوال ال‬


data.containsKey("name") -> true or false
data.containsValue(5) -> true or false
Map ‫الضافة عنصر جديد على‬
data["address"] = "Gaza";

data.putIfAbsent("name" , () => "saeed");


‫ غير موجود\ ال‬key‫ لم يكن موجودا وفي حال كان ال‬key‫ في حال ال‬Map ‫تقوم باضافة العنصر الى‬
‫يتم التعديل عليه وإنما يبقى كما هو‬
‫‪9‬‬

‫لتحويل ال‪ keys‬الى ‪List‬‬


‫‪;)(List keys = data.keys.toList‬‬
‫وكذلك يمكن تحويلها الى ‪Set‬‬
‫;)(‪Set keys = data.keys.toSet‬‬

‫‪:Enum in dart‬‬
‫يستخدم لتعريف مجموعة قيم ثابتة مثل أيام األسبوع أو مثال األشهر أو فصول السنة ‪Enum:‬‬
‫وهكذا‬
‫يفضل تسميته بالبدء بحرف كبير والقيم الخاصة به بحرف صغير ويتم تعريفه خارج المين ويشبه‬
‫تعريف الكالس‬
‫ال يمكن تعريف أرقام بداخله فقط كلمات‬
‫} ‪enum Seasons { winter, spring, summer, autumn‬‬
‫{ )(‪void main‬‬
‫;‪  Seasons first = Seasons.autumn‬‬
‫اليجاد اسم العنصر ‪  print(first.name); //‬‬
‫اليجاد موقع العنصر علما بأن العد يبدأ من صفر ‪  print(first.index); //‬‬
‫اليجاد\ نوع العنصر وفي هذه الحالة\ يكون ‪  print(first.runtimeType); //Seasons‬‬
‫}‬
‫‪:Functions in dart‬‬
‫{ )(‪void printHello‬‬
‫;)"‪  print("Hello‬‬
‫}‬
‫دالة ‪ void‬تقوم بطباعة ‪ Hello‬عند استداعاءها\ في ال‪ main‬ال توضع داخل جملة طباعة ألنها من‬
‫نوع ‪void‬‬
‫هكذا يتم استدعاءها ;)(‪printHello‬‬

‫{ )‪int sum(int x , int y‬‬


‫;‪  return x + y‬‬
‫}‬
‫‪10‬‬

‫نستخدمها في حالة كانت ال ‪function‬بها سطر واحد (طريقة مختصرة) ‪Another way:‬‬
‫‪;int sum(int x , int y) => return x + y‬‬
‫دالة ‪ int‬تقوم بجمع عددين\ عند استداعاءها في ال‪ main‬توضع داخل جملة طباعة\ ألنها من نوع‬
‫‪int‬‬
‫;))‪print(sum(7 , 8‬‬ ‫هكذا يتم استدعاءها\‬

‫مهم جدا جدا ‪Parametes type in function:‬‬


‫المدخالت المرتبة االجبارية ‪1. Positional parameters‬‬
‫هي مدخالت\ اختيارية االدخال اجبارية الترتيب (في حال أردنا إدخالها يجب إدخالها بشكل‬
‫مرتب بمعنى أنه لو كان عندنا ‪ 2‬قيم اختيارية ونريد إدخال قيمة لثاني مدخل يجب أن‬
‫ندخل قيمة لألول ثم للثاني ألننا مقييدين\ بالترتيب)‬

‫بمعنى اذا كان للدالة مدخالن االول سترنج والتاني ‪int‬‬


‫فيجب تمرير القيمتين وكما هي مرتبة‬
‫{ )‪void info(String name , int age‬‬
‫;) "‪  print( "$name and my age is $age‬‬
‫}‬
‫; )‪void info( "Ahmed", 22‬‬
‫هنا مررنا المدخلين وكما هي مرتبة\ وكالهما اجباريان ال يمكن االستغناء عن أحد منهما ( يحدث‬
‫ايرور)‬

‫‪2. Optional positional parameters‬‬


‫يتم وضعهم داخل [] ويجب أن نعطيهم قيم افتراضية‬

‫قيم افتراضية }{ )]"" = ‪void info([int age = 0 , String address‬‬

‫هنا مررنا القيم األولى ولم نمرر األخرى الن المدخالت اختيارية ;)‪info(15‬‬

‫مالحظة مهمة جدا‪ :‬ال نستطيع أن نعطي قيمة للعنصر التاني قبل أن نعطي لألول يجب أن نلتزم‬
‫بالترتيب\‬
‫هكذا ايرور ألننا أعطينا قيم للمتغير الثاني ‪ String‬ولم نعطي قيمة للمتغير األول ;)"‪info("ahmed‬‬
‫‪11‬‬

‫‪3. Optional named parameters‬‬

‫هي مدخالت\ اختيارية االدخال وغير اجبارية التمرير يتم اعطاء المتغير قيمة عن طريق\ اسم‬
‫المتغير‬

‫يتم وضعهم داخل {} ويجب أن نعطيهم قيم افتراضية أو نستخدم كلمة ‪required‬‬
‫الهدف من وضع قيمة افتراضية\ أو ‪ required‬هو الحماية من ال‪ null‬عندما نستخدم كلمة‬
‫‪ required‬يصبح المتغير اجباري التمرير‬

‫قيم افتراضية }{ )}"" = ‪void info({int age = 0 , String address‬‬


‫‪void info({required int age, required address = ""}) {} required‬‬

‫}{ )}"" = ‪void info({int age = 0 , String address‬‬

‫هنا مررنا القيم األولى ولم نمرر األخرى الن المدخالت اختيارية ;)‪info(age: 22‬‬
‫هكذا ايضا صحيح ألننا غير مجبرين\ بالترتيب\ وانما نمرر القيمة عن ;)"‪info("address" : "Gaza‬‬
‫طريق االسم‬

‫مالحظة‪ :‬يمكن الدمج بين النوع االجباري واالختياري في نفس ‪ funtion‬وال يمكن الدمج بين‬
‫نوعين االختياري ( ‪) optional positional , optional named‬‬

‫}{ )}"" = ‪void info(String name = "" , {int age = 0 , String address‬‬
‫هكذا ال‪ name‬اجباري التمرير\ و ال‪ age‬و ال‪ address‬اختياريين‬

‫;)"‪info(name = "ahmed" , "address" = "gaza‬‬


‫هنا مررنا ‪ name‬النه اجباري ومررنا\ ال‪ address‬من خالل االسم النه اختياري ال يحتاج\ لترتيب\ ولم‬
‫نمرر ‪ age‬النه اختياري‬
12

‫ أخرى‬function ‫ كمدخل ل‬function‫مالحظة يمكن تمرير\ ال‬

String capetalizeName(String name) {


  return name.toUpperCase();
}
‫دالة تحول النص ألحرف كبيرة‬

function ‫نالحظ هنا أن المدخل الثاني للدالة\ هو‬

String formatFullName(String fullName, Function function) {


  List<String> names = fullName.split(' ');
‫ تقوم بتقطيع النص بناء على رمز معين أو على المسافة‬split ‫دالة‬
  String firstName = function(names[0]); ‫تخزين\ المقطع األول من النص‬
  String middleName = function(names[1]); ‫تخزين\ المقطع الثاني من النص‬
  String lastName = function(names[2]); ‫تخزين المقطع الثالث من النص‬
  return firstName + ' ' + middleName + ' ' + lastName;
}

void main() {
  String fullName = "omar ahmed ali";
  String formatedName = formatFullName(fullName, capetalizeName);
‫ ومررنا لها مدخالن األول سترنج والثاني‬formatedFullName function ‫هنا قمنا باستدعاء‬
function capetalizedName
  print(formatedName);
}

OOP in Dart:

class Student{

String? name ;
int? age;
‫ أو نعطيهم قيم افتراضية‬null‫إما نجعلهم يقبلو ال‬
String name = "" ;
int age = 0;

}
13

‫ ال يحدث ايرور‬new ‫ ولو كتبنا‬new \‫مالحظة عند استدعاء الكالس داخل المين لسنا بحالة\ لكتابة‬
)‫ اختيارية ووجودها\ من عدمه ال يؤثر‬new ‫الطريقتان صحيحتان (كلمة‬

;)(Student stu = Student


;)(Student stu2 = new Student

: Dart ‫ في‬constructors‫أنواع ال‬


1. Un named constructor:

‫ العادي ويكون اسمه مثل اسم الكالس وال يمكن انشاء اكثر من واحد من‬constructor‫وهو ال‬
)‫هذا النوع (فقط واحد‬
class Student{

String? name ;
int? age;
double? gpa

Student (String? name , int? age , double? gpa){


this.name = name;
this.age = age;
this.gpa = gpa;
}

‫يمكن اختصاره بالشكل التالي‬:


Student(this.name , this.age , this.gpa);
}

2. named constructor:
‫ ويمكن انشاء‬Anyname. ‫ شبه العادي ويكون اسمه مثل اسم الكالس ثم‬constructor‫وهو ال‬
‫اكثر من واحد من هذا النوع‬
Student.one
Student.cons
Student.a
Student.abc
. ‫يمكننا كتابة أي اسم بعد‬
Student.first (String? name , int? age , double? gpa){
this.name = name;
this.age = age;
this.gpa = gpa;
}
14

Inheritance:
class Car{
String? name;
Car(String? name){
this.name = name;
}
}
‫ به مدخالت يجب تمرير\ هذه المدخالت‬constructor \‫ من كالس وكان لديه‬extends ‫عند عمل‬
super‫بواسطة كالس االبن عن طريق‬
class Skoda extends Car{
Skoda( String name ) : super (name);
}

)‫ ألكثر من كالس (فقط كالس واحد‬extends ‫ ال يمكن عمل‬:‫مالحظة مهمة‬

abstract Class:
abstract ‫ فيجب أن يكون‬abstract ‫اذا كان الكالس يحتوي على دالة من نوع‬
abstract ‫ فليس ضروريا أن يحتوي على دالة من نوع‬abstract ‫أما اذا كان الكالس‬

abstract class Car{


String getBrandName();(abstract) body ‫دالة ليس لها‬
int numOfWheels();
String model(){
return "model 2022";
}
}
) body ‫ ( فقط ال نضع لها‬abstract ‫ قبل الدالة التي من نوع‬abstract ‫نالحظ أنه ال نكتب كلمة‬

abstract ‫ لكل الدوال التي من نوع‬override ‫ يجب عمل‬abstract ‫عند الوراثة من كالس من نوع‬
‫ والباقي‬abstract ‫ لجميع الدوال (االجباري فقط التي من نوع‬override ‫وليس شرطا أن يتم عمل‬
)‫اختياري‬
class Bmw extends Car {
  @override
  String getBrandName() {
    return "Bmw";
 }
  @override
  int numOfWheels() {
    return 4;
 }
}
15

) ‫ او ال‬override ‫ (لدينا\ حرية\ بعمل‬abstract ‫ ألنها ليست‬model ‫ لدالة‬override ‫هنا لم نقم بعمل‬

:implements in Dart

‫ لجميع متغيرات‬override ‫ من كالس يجيب عمل‬implements ‫ عند عمل‬:‫مالحظة مهمة جدا جدا‬
‫ أم ال‬abstract ‫ودوال الكالس سواء كانت من نوع‬

abstract class Car {


  String name = "";

  String getBrandName();
  int numOfWheels();

  String model() {
    return "2022";
  }
}

class Bmw implements Car {


  @override
  String getBrandName() {
    return "Bmw";
  }

  @override
  int numOfWheels() {
    return 4;
  }

  @override
  String name = "Bmw 2022";

  @override
  String model() {
    return "model 2022";
  }
}
‫ لكل محتويات‬override ‫ وجب علينا أن نقوم بعمل‬implements ‫نالحظ أنه عندما قمنا بعمل‬
‫الكالس األب‬

‫ من أكثر من كالس‬implements ‫ يمكن عمل‬:‫مالحظة‬


‫‪16‬‬

‫‪:Mixins in Dart‬‬
‫من االضافات\ المميزة في لغة دارت والهدف منها أنه ال يمكننا عمل ‪ extends‬من أكثر من كالس‬
‫وفي نفس الوقت يمكننا عمل ‪ implements‬ألكثر من كالس ولكننا مجبرين لعمل ‪override‬‬
‫لجميع دوال ومدخالت كل كالس والعمليتان (‪ )extend , implements‬ليست كافيات ألن لكل‬
‫واحدة منها عيب ونحن بحاجة\ لحل فجاءت ‪ mixins‬لهذا السبب‬

‫بعد اسم الكالس نكتب ‪ with‬ثم اسماء الكالسات المراد عمل وراثة منها‬

‫{ ‪class Car‬‬
‫;‪  String? name‬‬
‫;‪  int? numOfWheels‬‬
‫{)‪int calculateSpeed(int speed‬‬
‫;‪return speed * 100‬‬
‫}‬

‫}‬

‫{‪class Machine‬‬
‫;‪int? motorPower‬‬
‫}‬

‫{ ‪class Bmw with Car , Machine‬‬


‫}‬

‫‪{)(void main‬‬
‫‪;)(Bmw bmw = Bmw‬‬
‫‪;bmw.motorPower = 5‬‬

‫من خالل األوبجكت الذي انشأناه نستطيع الوصول لجميع الدوال والمتغيرات بين الكالس وذلك‬
‫بفضل ‪mixins‬‬
‫}‬

‫مالحظة مهمة جدا جدا‪ :‬الكالس الذي نريد\ الوصول اليه من خالل ‪ with‬الخاصة ب ‪mixins‬‬
‫ال يمكن أن يحتوي على ‪ constructor‬اذا كان يحتوي على ‪ constructor‬يحدث ايرور‬

‫من اختصارات دارت أننا نستطيع الوصول للمتغير بعد انشاء األوبجكت مباشرة\ بطريقة مختصرة‬

‫"‪Bmw b = Bmw()..name = "ahmed‬‬


‫;‪..numOfWheels = 5‬‬
‫نالحظ أننا مررنا القيم في نفس جملة االنشاء‬
‫يسمى ‪cascading operator ..‬‬
‫‪17‬‬

‫أنوع المتغيرات داخل الكالس‪\:‬‬


‫‪{class Test‬‬

‫‪;const int x = 5‬‬

‫المتغير ‪ const‬متغير ال تتغير قيمته وجيب اعطاءه قيمة عن التعريف وال يمكن تغيير القيمة الحقا‬
‫وال يمكن أن يقبل ال‪null‬‬
‫‪;final int y‬‬

‫المتغير ‪ final‬متغير ال تتغير قيمته ويمكن اعطاءه قيمة مباشرة\ عند التعريف أو من خالل‬
‫‪ constructor‬وال يمكن أن يقبل ال‪ null‬وال يمكن تغيير القيمة الحقا‬

‫‪;static int z = 5‬‬


‫المتغير ‪ static‬متغير يمكن تتغير قيمته ويمكن اعطاءه قيمة مباشرة\ عند التعريف أو من خالل‬
‫‪ constructor‬و يمكن تغيير القيمة الحقا ويمكن أن تكون قيمته ‪null‬‬
‫}‬

‫مالحظة مهمة بخصوص ‪ : static‬يتم استدعاء من خالل اسم الكالس فقط ال يمكن استدعاءه‬
‫بعد تعريف األوبجكت ( فقط من اسم الكالس)‬

‫‪;test.z = 8‬‬

‫‪;)(Test t = Test‬‬
‫هكذا ايرور ألن المتغير من نوع‪static‬يتم استدعاءه\ من اسم الكالس فقط ;‪t.z = 10‬‬

‫‪:Introduction to Flutter‬‬
‫لكي نقوم بعمل ‪ run‬لتطبيق فالتر\ نستخدم دالة ال‪runApp‬‬

‫{ )(‪void main‬‬
‫‪ MyApp‬هو الويدجت\ التي سنقوم بعمل ‪run‬لها ;))(‪runApp(const MyApp‬‬
‫}‬

‫‪Every thing in flutter is a widget‬‬


‫‪18‬‬

‫تشبه‪constructor‬ويكون بها عدة مدخالت\ منها اجباري ومنها\ اختياري ‪Widget:‬‬

‫فمثال ‪ )(Text‬بها متغير اجباري وهو ‪ String‬وبها عدة متغيرات اختيارية مثل ‪ style‬وغيرها\‬

‫عبارة عن الويدجت الرئيسية لتطبيق فالتر\ وال يمكن أن نقوم بعمل رن للتطبيق ‪Material App:‬‬
‫وهي غير موجودة وتوجد\ مرة واحدة داخل التطبيق‬

‫هنا ازلنا ال ‪ MaterialApp‬وهكذا سيكون الناتج بدونها‬


‫يظهر لنا ‪ exception‬اسمه ‪No MediaQuery‬‬
‫‪19‬‬

‫هناك نوعين رئيسين من الويدجت في فالتر وهما ‪ Stateless Widget‬واالخر ‪Stateful Widget‬‬
‫كالهما عبارة عن ‪ abstract class‬يرث من الكالس األب لهما وهو ‪Widget‬‬

‫وبما أنها ‪ abstract‬فيجب علينا عند عمل ‪ extends‬منهم يجب علينا أن نقوم بعمل ‪override‬‬
‫لدالة ‪ build‬التي هي داخلهما ومن\ نوع ‪abstract‬‬

‫هنا كالس ‪ MyApp‬من نوع ‪ Widget‬ألنه يرث من‬


‫كالس ‪ StatelessWidget‬الذي يرث من الكالس‬
‫الرئيسي هو ‪ Widget‬وبما أنه قمنا بعمل ‪extends‬‬
‫له يجب أن نقوم بعمل ‪ override‬لدالة ال‪build‬‬
‫حتى ال يحدث أي ايرور وللعلم أن دالة ‪build‬‬
‫تقوم بارجاع ‪ Widget‬فقمنا بارجاع ال‪Widget‬‬
‫الرئيسية التي يجب أن تكون داخل التطبيق مرة‬
‫واحدة وهي ال‪ MaterialApp‬حتى ال يحدث‬
‫‪exception‬‬

‫مالحظة‪ MaterialApp :‬ترث من ‪ StatefulWidget‬وبالتالي هي ‪Widget‬‬


‫‪ MaterialApp‬وظيفتها معرفة ابعاد الشاشة المراد تشغيل التطبيق عليها (ايفون ‪ ,‬تابلت ‪ ,‬تلفاز‬
‫وغيرها) تقوم بمعرفة ابعاد الشاشة لكي يتم بناء الواجهة بشكل صحيح‬
‫‪20‬‬

‫هنا ناتج الرن بوجود ال‪ MaterialApp‬فقط شاشة سوداء وظيفتها‬


‫معرفة ابعاد شاشة\ الجهاز المراد تشغيل التطبيق عليه‬

‫لكي نظهر شاشة بيضاء للبدء\ بوضع المحتوى عليها كما في برنامج الرسام الكوجود على ويندوز\‬
‫نستخدم ال‪ Widget‬التي اسمها ‪ Scaffold‬ويتم وضعها داخل ال‪ home‬والمقصود بال‪ home‬هي‬
‫الشاشة نفسها بمعنى أن الشاشة تحتوي على ‪Scaffold‬‬

‫نالحظ هنا باستخدام ال‪ Scaffold‬اصبحت الشاشة بيضاء\ وجاهزة لوضع‬


‫العناصر عليها‬
‫‪21‬‬

‫لكي نزيل العالمة\ الحمراء الموجودة في اعلى يمين الشاشة نستخدم هذا الكود‬
‫‪debugShowCheckedModeBanner: false,‬‬

‫نكتب داخل أقواس ال‪MaterialApp‬‬


‫وسبب وجود\ العالمة الحمراء أن التطبيق الذي نقوم بكتابه هو تطبيق تجريبي يتم استخدامه من‬
‫المبرمج نفسه ( تطبيق عادي تجريبي ليس مثل تطبيقات متجر ‪ ) Google play‬وتسمى نسخة‬
‫التطبيق ‪ apk‬وال يمكن رفعها على المتجر عند االنتهاء من التطبيق كامال يتم تحويله\ لنسخة ‪app‬‬
‫وهي النسخة التي يقبل بها المتجر‬

‫نالحظ أن العالمة اختفت تماما\ من أعلى يمين الشاشة عندما‬


‫استخدمنا ‪,debugShowCheckedModeBanner: false‬‬

‫المختصر إلى حد االن أن كل شيء عبارة ‪ Widget‬و هناك نوعان رئيسان من ‪ Widgets‬وهما‬
‫‪ Stateless‬و ‪ Stateful‬وهما من نوع ‪ abstract‬وبها دالة ‪ build‬يجب عمل ‪ override‬لها والتطبيق‬
‫يجب أن يحتوي على ال‪ MaterialApp‬مرة واحد فقط وبدونها يظهر لنا ‪ exception‬عند الرن وهي‬
‫تقوم بحساب أبعاد الشاشة المراد تشغيل التطبيق عليها وكل واجهة بالتطبيق\ لها ‪Scaffold‬‬
‫خاص بها يتم وضعه داخل ال‪ home‬وهو الشاشة البيضاء\ التي يتم وضع العناصر عليها والزالة‬
‫العالمة\ الحمراء في أعلى يمين الشاشة نستخدم ‪debugShowCheckedModeBanner: false‬‬
‫ونضعه داخل ‪MaterialApp‬‬
‫‪22‬‬

‫لتغيير لون الشاشة نستخدم ‪ backgroundColor‬داخل ‪ Scaffold‬ويتم اعطاءه القيمة ب‪ 3‬طرق‬


‫مختلفة أما باسم اللون او ‪ hexa‬أو ‪ RGB‬وهنا بالكود الثالث طرق‬

‫نالحظ أن اللون الخلفية قد تغير وكما هو موضح بالكود أعاله ‪ 3‬طرق‬


‫لتغيير لون الخلفية واستخدمنا\ ‪ const‬وظيفتها ليست ازالة الخطوط من‬
‫تحت الكود إنما وظيفتها عزل ال‪ Widget‬عن ال‪ runtime‬والهدف من‬
‫ذلك زيادة سرعة التطبيق‬
‫المقصود\ بسرعة التطبيق هي ‪ ( performance‬بمعنى وجود ال‪const‬‬
‫مفيد للتطبيق وغالبا\ ما يتم وضعها مع القيم الثابتة\ مثل درجة اللون‬
‫أول طول أو عرض أو نص وهكذا )‬
‫مالحظة‪ :‬الخطوط الصفراء عبارة عن تنبيه ليس أكثر‬

‫مالحظة يتم تقسيم الشاشة في تطبيق إلى ثالث أقسام وهي ‪ AppBar‬و ‪ body‬و ‪bottom‬‬
‫‪navigation bar‬‬

‫‪AppBar‬‬

‫‪Body‬‬

‫‪Bottom Navigation bar‬‬


‫‪23‬‬

‫لوضع نص في منتصف أي مساحة نستخدم ‪ Center‬ولها مدخل\ يمسى ‪ child‬يتم وضع النص من‬
‫خالله‬

‫قمنا بوضع ال‪ Center‬داخل ال‪ body‬وال‪ Center‬لها مدخل ‪child‬‬


‫تم وضع ال‪ Text‬بداخله وقمنا\ باعطاء ال‪ Text‬بعض الخصائص‬

‫باستخدام ‪ TextStyle‬الموجود بداخل المدخل ‪ style‬الخاص ب ‪ Text‬قمنا‬


‫باعطاءه حجم ‪ 30‬و لون أحمر ونوعه الخط غامق\‬

‫لكي نقوم بوضع ال‪ appBar‬في أعلى الشاشة نستخدم ال‪ Widget‬التي اسمها ‪AppBar‬‬
‫وال يهم الترتيب بين ال‪ appBar‬و ال‪ body‬و ال‪bottomNavigationBar‬‬
‫‪24‬‬

‫نالحظ أن ال‪ appBar‬ظهر لدينا وقمنا باعطاءه ‪ title‬عبارة عن نص باستخدام ال‪Text‬‬


‫للتذكير\ كلمة ‪ const‬وظيفتها ليست ازالة الخطوط الصفراء وانما عزل العنصر عن ‪ runtime‬لزيادة‬
‫ال‪ performence‬ويتم استخدامها عادة مع الثوابت مثل اللون و الطول و العرض و النص وغيرها\‬

‫‪:Column and Row Widgets‬‬


‫لترتيب العناصر بشكل عمودي ‪Column:‬‬
‫لترتيب العناصر بشكل أفقي ‪Row:‬‬
‫كالمهما يقبل مجموعة من ال‪ Widgets‬يتم وضع هذا ال‪ Widgets‬داخل مدخل يسمى ‪children‬‬
‫نفس فكرة ال‪ Center‬لها ‪ child‬هنا نفس الشيء ولكن ‪children‬‬
‫‪25‬‬

‫ترتيب العناصر بشكل عمودي‪Colum:‬‬

‫نالحظ أن النصوص ظهرت بشكل عمودي ألنها موضوعة‬


‫داخل ‪ childern‬الخاصة ب ‪Column‬‬

‫ترتيب العناصر بشكل أفقي‪Row:‬‬

‫نالحظ أن النصوص ظهرت بشكل أفقي ألنها موضوعة‬


‫داخل ‪ childern‬الخاصة ب ‪Row‬‬
26

: Column‫ و ال‬Row‫مثال يدمج ما بين ال‬


Map<String, dynamic> map = {
"name": "Ahmed Jameel Abu Nasser",
"age": 23,
"isMale": true,
"University": "IUG"
};
‫ تحتوي على بيانات طالب ونريد عمل واجهة الظهار هذه المعلومات‬map ‫لنفرض أن لدينا‬
‫ ألننا سنقوم بعرضها بشكل عمودي ( االسم في السطر األول والعمر‬Column ‫اوال نحتاج لعمل‬
‫ لعرض االسم وقيمته والعمر وقيمته بشكل‬Row ‫ نحتاج الى‬Column‫في التاني وهكذا) وداخل ال‬
‫ يمثل صف من البيانات‬Row ‫ كل‬Row 4 ‫ بداخله‬Column \‫أفقي فسيصبح لدينا‬

return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text("HOME"),
),
body: Column(
children: [
Row(
children: [
Text("name: "),
Text(map["name"]),
],
),
Row(
children: [
Text("age: "),
Text(map["age"].toString()),
],
),
Row(
children: [
Text("isMale"),
Text(map["isMale"] ? "Male" : "Female"),
],
),
Row(
children: [
Text("University"),
Text(map["University"]),
],
),
],
),
),
);
}
}
‫‪27‬‬

‫الضافة صورة من االنترنت نستخدم ال‪ Widget‬التي اسمها ‪Image‬‬


‫)"‪Image.network("url‬‬

‫هكذا يكون الناتج ( يجب التأكد أن الرابط صحيح وفعال)‬


‫‪28‬‬

‫اذا كنا نضيف اضافة صورة من الجهاز (صورة موجودة مسبقا لدينا) يتم تفعيل ال‪ assets‬في ملف‬
‫‪( pubspec.yaml‬لغة ‪ yaml‬هي لغة تعتمد على مبدأ االزاحات (المساطر))‬

‫عند فتح ملف ‪ pubspec.yaml‬نقوم بازالة الكومنت عن ‪ assets‬ووضع مسار الصورة‬


‫نقوم بانشاء مجلد نسميه ‪ images‬ونضع الصورة بداخله\ قم نقوم بنسخ مسار الصورة‬

‫بعد ازالة الكومنت عن ‪ assets‬ووضع مسار الصورة يصبح الشكل هكذا‬

‫التكملة في الصفحة ‪<----- 29‬‬


‫‪29‬‬

‫هذه تابعة لصفحة ‪28‬‬


‫نذهب للكود ونضع مسار الصورة عن طريق )‪Image.assets(url‬‬

‫وهكذا قمنا بعرض صورة موجودة لدينا مسبقا‬

‫اذا اردنا حجز مكان بالواجهة\ بحجم معين نستخدم ال‬


‫‪ Widget‬التي اسمها ‪Container‬‬
‫وظيفتها حجز مساحة لوضع العناصر فيها نستطيع أن نضع فيها ما نشاء ‪Column , Row , Image‬‬
‫‪ ,Text‬وغيرها‬
‫‪30‬‬

‫يكون الناتج هكذا مساحة ال‪ Container 200 * 200‬والخلفية سوداء وبداخله ‪ Column‬به نصان‬

‫يوجد لل‪ Column‬و ‪ Row‬خواص كثيرة أهمها ال‪ Alignment‬وتكون على قسمين‪:‬‬
‫وهو المحور الرئيسي ‪mainAxisAlignment‬‬
‫‪31‬‬

‫وهو المحور المعاكس اذا كان ‪crossAxisAlignment‬‬


‫المحور الرئيسي ل ‪ Cloumn‬هو العمودي والمعاكس هو األفقي‬
‫المحور الرئيسي ل ‪ Row‬هو األفقي والمعاكس هو العمودي‬

‫تستخدم ال‪ Alignment‬لتغيير موضوع العنصر في الواجهة سواء ل‪ Column‬أو ‪Row‬‬


‫في حالة ال‪: Column‬‬
‫‪crossAxisAlignment: CrossAxisAlignment.center‬‬
‫‪mainAxisAlignment: MainAxisAlignment.end‬‬
‫بمعنى جعل المحتوى في منتصف الواجهة افقيا وفي اخر الواجهة عموديا‬

‫في حالة ال‪: Row‬‬


‫‪crossAxisAlignment: CrossAxisAlignment.center‬‬
‫‪mainAxisAlignment: MainAxisAlignment.end‬‬
‫بمعنى جعل المحتوى في منتصف الواجهة عموديا وفي اخر الواجهة افقيا‬

‫مالحظة‪:‬‬
‫بشكل افتراضي يأخذ ال‪ Column‬حجم الشاشة عموديا ويأخذ حجم أكبر عنصر فيه افقيا‬
‫وال‪ Row‬ياخذ حجم الشاشة عرضيا ويأخذ\ حجم أطول عنصر فيه عموديا‬

‫اذا اردنا إعطاء ال‪ Column‬كامل الحجم أفقيا نكتب ‪width: double.infinity‬‬
‫اذا اردنا إعطاء ال‪ Row‬كامل الحجم عمويا نكتب ‪height: double.infinity‬‬

‫هنا أردنا أن نعمل فاصل\ ما بين عنصرين\ مثال لدينا\ نص ثم صورة ثم نص ونريد\ عمل فاصل بينهم‪\:‬‬
‫‪32‬‬

‫نالحظ أن العناصر ملتصقة ببعضها‬


‫اذا اردنا أن نعمل فاصل بينهم نستخدم ‪)(SizedBox‬‬

‫عند استخدام ال‪ )(SizedBox‬يكون الناتج كالتالي‪\:‬‬

‫نالحظ أنه باستخدام )‪ SizedBox(height:30‬أصبحت هناك‬


‫مسافة واضحة بين العناصر‬

‫في حال كان لدينا ‪ Column‬وكان لدينا عناصر ال يكفي عرضها في الشاشة سيظهر لنا كالتالي‪:‬‬
‫‪33‬‬

‫الخط االصفر مع االسود يعني أن المحتوى المراد عرضه أكبر‬


‫من حجم شاشة الهاتف وفي هذه الحالة\ يجيب أن نفعل‬
‫‪ scroll‬لكي نستطيع من إظهار كامل المحتوى‬
‫نستطيع أن نستخدم ‪ SingleChildScrollView‬أو نستخدم‬
‫‪ listView‬بدال من ال‪Column‬‬

‫الحالة األولى ‪SingleChildScrollView‬‬


‫‪34‬‬

‫نالحظ أنه عندما استخدمنا\ ‪ SingleChildScrollView‬اصبح‬


‫بامكاننا عمل ‪ scroll‬على المحتوى دون مشاكل‬

‫هناك حل اخر لمشكلة أن حجم الشاشة ال يكفي لما نحتاج لعرضه الطريقة األولى هي‬
‫‪ SingleChildScrollView‬والثانية هي باستخدام ‪listview‬‬
‫واستخدام ال‪ listview‬أفضل للتطبيق من استخدام ‪SingleChildScrollView‬‬
‫التكملة في صفحة ‪<<<<35‬‬
‫‪35‬‬

‫نالحظ عند استخدام ‪ listview‬قمنا بعرض كامل المحتوى بدون مشاكل‬


‫اذا أردنا تغيير اتجاه العرض في ال‪ listview‬نستخدم ‪scrollDirection: Axis.vertical‬‬ ‫‪‬‬
‫بشكل افتراضي يكون االتجاه ‪ vertical‬ونستطيع تغييره إلى ‪horizontal‬‬

‫اذا أردنا عكس ترتيب المحتوى نستخدم ‪reverse:true‬‬ ‫‪‬‬

‫هناك شكل اخر من اشكال ال‪ listview‬وهو ‪ListView.builder‬‬


‫التكملة في صفحة <<< ‪36‬‬
36

‫ بها مدخل اجباري وهو‬ListView.bulilder ‫ وهو‬listview‫هنا الشكل االخرمن\ ال‬


{ itemBuilder: (BuildContext context, int index)
return Widget; widget ‫تقوم بارجاع‬

}
listview‫ هي الواجهة الموجود\ بها ال‬BuildContext context
‫ ويبدأ من صفر‬listview‫ هو ترقيم لمواقع العناصر في ال‬int index
‫ وهي ويدجت جاهزة من‬ListTile ‫ هي‬return ‫ التي قمنا بإرجاعها\ في‬widget‫في المثال ال‬
flutter

ListTile Widget

leading: const Icon(Icons.list)


Leading: const Text(“GFG”)

title: Text(“List item $index”));

itemCount: 5 ‫ عناصر كما هو موضح في‬5 ‫هو عدد العناصر المراد عرضها وفي هذه الحالة هي‬
‫شاشة الرن‬
‫‪37‬‬

‫لتغيير ‪ theme‬للواجهة من أبيض ألسود أو العكس نقوم بالتالي‬


‫أوال نقوم بتعريف متغير للحالة\ ‪;bool isDark = false‬‬

‫الويدجت ‪ Theme‬هي التي تتحكم بال‪ theme‬عن طريق المدخل الخاص بها ‪data‬‬
‫‪,)(Data: isDark ? ThemeData.dark() : ThemeData.light‬‬
‫هو المتغير الذي قمنا بتعريفه ‪isDark‬‬
‫‪ if‬مختصرة\ لفحص اذا كان ترو أو فولس ? ‪isDark‬‬
‫اذا كان المتغير ترو فيتم تنفيذ أول خيار بعد عالمة االستفهام وهو الدارك ثيم‬
‫‪ )(ThemeData.dark‬واذا كان فولس يتم تنفيذ الاليت ثيم ‪)(ThemeData.light‬‬
‫يتم التبديل بينهم من خالل ‪ Switch‬وهي ويدجت‬
‫الحالة الموجودة حاليا\ ‪Value: isDark,‬‬
‫عند الضغط على ‪ switch‬يتم تغيير الحالة\ من اليت لدراك والعكس{ )‪onChange: (val‬‬
‫;‪isDark = val‬‬
‫بدونها ال يتم التبديل\ ;)}{ )( (‪setState‬‬
‫}‬
‫‪Switch Widget‬‬
‫‪38‬‬

‫إلنشاء حقل للكتابة فيه نستخدم ‪TextField‬‬

‫;)(‪TextEditingController nameController = TextEditingController‬‬

‫هذا الكالس هو المتحكم بال‪TextField‬‬

‫‪ Container‬لوضع الحقل فيه وقمنا‬


‫باعطائه ‪ color‬وحواف دائرية من خالل‬
‫‪ borderRadius‬و ‪ margin‬و ‪padding‬‬
‫ال‪ Row‬هو السطر المكون من كلمة‬
‫‪ Name‬و ‪TextField‬‬
‫‪ Expanded‬تستخدم لعمل مسافة بين‬
‫العنصرين المتجاورين وال‪ controller‬هو‬
‫المتحكم في ال‪ TextField‬وقمنا باعطاءه‬
‫قيمة وهو األوبجكت من ‪ ;)(TextEditingController‬الذي تم انشاءه في األعلى وبدونه\ لن‬
‫نستطيع التعامل مع ‪ TextField‬مثل اخذ القيمة المكتوبة فيه او عند الضغط عليه (بمعنى يتحكم‬
‫بالحدث الذي يحدث على ‪)TextField‬‬
39

RadioButton ‫إلنشاء‬
String gender = "";

Container(
margin: const EdgeInsets.all(10), ‫مارجن للكونتينر‬
padding: const EdgeInsets.all(10), ‫بادينج للكونتينر‬
decoration: BoxDecoration(
color: Colors.greenAccent,‫اعطاء لون للكونتينر‬
borderRadius: BorderRadius.circular(15)),‫حواف دائرية للكونتينر‬ ‫اعطاء‬
child: Row(
children: [
const Text("Gender: "),‫نص توضيحي للحقل‬
Expanded(
child: Column(
children: [
Row( ‫لعرض الحقل بجانب االسم بشكل افقي‬
children: [
Radio( Radio Widget ‫اختيار شيءواحد فقط‬
value: "m"‫القيمة الخاصة بالزر‬
groupValue: gender,
onChanged: (v) {‫لتغير حالة الزر عن الضغط عليه‬
gender = "m";
setState(() {});‫ال يحدث التغيير بدونها‬
}),
const Text('Male')
],
),
Row(
children: [
Radio(
value: "f",
groupValue: gender,
onChanged: (v) {
gender = "f";
setState(() {});
}),
const Text('FeMale')
],
)
],
),
)
],
),
),
‫ االول والثاني وذلك\ كي نستطيع أن نختار واحد‬Radio‫ موحد عن كل من ال‬groupValue ‫نالحظ أن‬
‫منها فقط‬
‫الناتج من الكود السابق هكذا‬
40

checkBox ‫لعمل‬
List<Certificate> certifications = [
Certificate("Diploma"),
Certificate("Ba"),
Certificate("Master"),
Certificate("PHD"),
];

class Certificate {
String name;
bool isSelected = false;

Certificate(this.name);
}

CheckBox
‫ للبدء\ من أول‬Aligment.stat
)‫الواجهة (اليسار‬
Childern: certifications.map( (e) )
‫ التي تم انشاؤها‬list ‫لعمل لوب على‬
checkBox ‫في االعلى بدال من تكرار‬
‫عدة مرات‬

isSelected , name ‫هي متغيرات خاصة بالكالس‬


Value: e.isSelected‫بمعنى فحص اذا كان الحقل مختار أم ال‬
onChange: (v) {
e.isSlected = !e.isSelected ‫بمعنى اذا كان مختار وتم الضغط عليه سيتحول الى غير مختار‬
setState( () {}); ‫بدونها ال يتم التغيير‬
}
Text(e.name) ‫اسم العنصر من خالل ال‬
‫‪41‬‬

‫إلنشاء زر‬

‫النص المكتوب على الزر )”‪Text(“Send‬‬


‫الحدث الذي سيحدث عن الضغط على الزر } { )( ‪onPressed:‬‬
‫مثل االنتقال لواجهة أخرى أو االنتقال لواجهة أخرى مع نقل البيانات\ من الواجهة للواجهة االخرى‬

‫هاد ممكن يجي باالمتحان كسؤال صحح الخطأ والتصحيح تبعه أنو نحط ثالث نقاط قبل‬
‫‪certification‬‬
‫الخطأ انو ‪ certification‬هي ‪ list‬وال‪ return‬بتتعامل مع عنصر واحد فقط فلما نحط ثالث نقاط بحول‬
‫ال‪ list‬لعنصر عنصر بدل من مجموعة\ وحدة‬
‫‪42‬‬

‫لالنتقال من واجهة لواجهة اخرى نقوم بكتابة التالي‪:‬‬


‫{ ) )‪Navigator.of(context).push(MaterialPageRoute ( bulider: (context‬‬
‫;اسم الواجهة ‪return‬‬
‫}‬
‫هذا الكود نضعه مثال في ‪ onPressed‬لل‪ ElevetedButton‬لكي ننتقل عند الضغط على الزر‬
‫هذه الطريقة األولى وهناك أكثر من طريقة له‬

‫هذا تكملة لواجهة الفورم عند الضغط على زر ‪ send‬هنجيب االسم الي دخله اليوزر في حقل‬
‫االسم وهل ذكر أم أنثى والشهادات\ الحاصل عليها ( التي تم اختيارها\ من ‪)CheckBox‬‬
‫هو عبارة عن كالس قمنا بانشاءه ‪InfoArguements‬‬

‫تكملة في الصفحة التالية <<<<<< ص‪43‬‬


‫‪43‬‬

‫)‪" , arguments: InfoArguments‬اسم الواجهة"(‪Navigation.of(context).pushNamed‬‬


‫نستطيع من خاللها االنتقال لواجهة اخرى ويمكننا العودة لنفس الواجهة ‪pushNamed‬‬
‫كما يحدث في التنقل بين شاشات التطبيق‬
‫‪arguments: InfoArguments‬‬
‫المقصود\ بها أن هذه هي البيانات\ التي سيتم ارسالها من الواجهة االولى وهي واجهة الفورم‬
‫الى الواجهة االخرى وهي واجهة العرض و‪ InfoArgument‬هو ‪ object‬من الكالس ‪InfoArgument‬‬
‫وهو يتكون من اسم وجنس وشهادات كما هو موضح في الصفحة السابقة ( ص ‪)42‬‬
‫وال‪ arguments‬هو مدخل اختياري بمعنى أنه ليس شرطا عن االنتقال من واجهة لواجهة أخرى‬
‫أن نقوم بارسال بيانات ( حسب الحاجة نستخدمها)‬

‫الستقبال البيانات في الواجهة األخرى‬


‫= ‪infoArguments‬‬
‫;?‪ModalRoute.of(context)?.settings.arguments as InfoArguments‬‬
‫نستخدم هذا الكود وما تحته خط هو اسم الكالس الذي قمنا بارساله\ من الواجهة االولى‬

‫هناك أيضا طريقة أخرى للتنقل بين الواجهات وهي طريقة ال‪ Routes‬وهي طريقة يتم فيها تعريف‬
‫اسم لكل واجهة ويتم استدعاءها\ من خالل االسم‪:‬‬
‫{ ‪routes:‬‬
‫‪"userForm": (context) => const UserFormPage(),‬‬
‫‪"userInfo": (context) => UserInfoPage(),‬‬
‫)(‪"PageNotFound": (context) => const PageNotFound‬‬
‫‪},‬‬
‫ثم نستخدم ال‪Navigation‬‬
‫) "‪Navigation.of(context).pushReplacementNamed("userForm‬‬
‫) "‪Navigation.of(context).pushReplacementNamed("userInfo‬‬
‫نستخدمها\ في حال أردنا أن ننتقل إلى واجهة دون الحاجة الى ‪pushReplacementNamed‬‬
‫العودة الى الواجهة السابقة مثل االنتقال من اللوجن الى الصفحة الرئيسية لسنا بحاجة الى‬
‫العودة الى اللوجن‬
44

‫ وهو تنقل في محتوى الواجهة كما في فيس بوك‬TabBar ‫لعمل‬

TabBar

DefaultTabController‫هو المتحكم في التاب بار‬


Lenght: 3 3 ‫بمعنى أن عدد العناصر هو‬
( bottom: const TabBar
tabs: [
Tab(icon: Icon(Icons.flight)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_car)),
],

45 <<<<<< ‫تكملة في صفحة‬


45

TabBarView(‫هو المحتوى الذي سيعرض عن الضغط على تاب معينة‬


children: [
Icon(Icons.flight, size: 350),
Icon(Icons.directions_transit, size: 350),
Icon(Icons.directions_car, size: 350),
],
‫‪46‬‬

‫هناك محتوى جانبي يظهر عن الضغط على أيقونة في ال‪ appBar‬يسمى هذه المحتوى الجانبي‬
‫‪Drawer‬‬

‫عند الضغط عليه يظهر ‪Drawer‬‬

‫هذا المحتوى الجانبي هو ال‪Drawer‬‬


‫مثال اخر على ‪:Drawer‬‬

‫‪ Drawer‬يستخدم لعرض محتوى جانبي مثل صورة للمستخدم‬


‫وبيانات عنه وأيقونات تنقل مثل المفضلة وسلة\ المحذوفات‬
‫واالعدادات وزر تسجيل الخروج وهكذا‬

‫الكود بالصفحة التالية\ <<<< ص ‪47‬‬


47

children ‫ له‬Coulmn‫ وال‬Column ‫ بداخله‬Drawer


‫ ويكون بها البيانات الشخصية عن المستخدم‬Drawer‫ هي رأس ال‬UserAccountDrawerHeader
‫مثل اسمه ايميله وصورة شخصية‬

‫يستخدم لجعل شكل الصورة دائري‬CircularAvatar

‫لون خلفية الصورة يظهر عندما يكون حجم الصورة اصغر من‬
‫الدائرة‬
const UserAccountsDrawerHeader(
accountName: Text("Ahmed"),‫اسم المستخدم‬
accountEmail: Text("Ahmed@gmail.com"),‫ايميل المستخدم‬
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.white,‫خلفية الصورة بيضاء‬
backgroundImage: AssetImage('assets/images/image0.jpg'),
),
),
‫امتداد الصورة من ملفات المشروع‬
48

ListTile

leading

trailing

ListTile
title

leading: ‫األيقونات التي في اليسار‬


trailing: ‫األيقونات التي في اليمين‬

ListTile(
leading: const Icon(Icons.favorite_outline),
title: const Text("Favourite"),
subtitle: const Text("menu"),
trailing: IconButton( ‫زر على شكل أيقونة‬
onPressed: (){}, ‫الحدث الذي سينفذ عند الضغط على الزر‬
icon: const Icon(Icons.arrow_forward_ios)
),
)
‫‪49‬‬

‫‪PageView in Flutter‬‬
‫مبدأها مثل ال‪ listview‬ولكن تختلف عنها أن كل عنصر موجود\ بداخلها\ يمثل واجهة مستقلة‬
‫بمعنى ال‪ listview‬تعرض العناصر بشكل أفقي أو عمودي في نفس الواجهة أما ال‪pageView‬‬
‫تعرض العناصر بشكل أفقي في واجهات وليس في نفس الواجهة ويكون عدد الواجهات حسب‬
‫عدد عناصرها ( ‪ 3‬عناصر ‪ 3‬واجهات وهكذا) يتم التنقل ما بين الواجهات عن طريق\ ال‪ Scroll‬من‬
‫اليسار لليمين\ كما في فيسبوك كما التنقل في واتساب ما بين المحادثات والحالة\ والمكالمات‬
‫;‪int currentPageIndex = 0‬‬
‫;)(‪PageController pageController = PageController‬‬

‫)المتغير التي تم تعريفه في األعلى( ‪Controller : pageController‬‬


‫وظيفة ال‪ controller‬هو التحكم في الشاشات ( التحكم في عرضها او التحكم في طريقة ال‬
‫‪ scroll‬بين الشاشات)‬
‫دالة تنفذ عن االنتقال من واجهة الخرى }{)‪onPageChanged(value‬‬
‫) )هو رقم الواجهة التي نحن بداخلها علما أن العد يبدأ من ‪value0‬‬
‫‪currentPageIndex‬‬
‫ونأخذ قيمته من متغير قمنا بتعريفه كل نصل الى رقم الواجهة التي نحن فيه ‪ value‬وفائدته أنه‬
‫من خالل رقم الواجهة نستطيع عمل حدث مستقل لكل شاشة كما نشاء‬

‫هي العناصر التي سيتم التنقل بينهم في‪pageView‬وهم عبارة عن ثالث واجهات ‪Childeren‬‬
50

Page1 index 0 Page2 index 1 Page3 index2


scroll‫ نستطيع التنقل بينها عن طريق\ ال‬pageView ‫ واجهات الموجودة في‬3‫هذه هي ال‬
Bottom Navigation Bar ‫وهناك طريقة اخرى للتنقل بينهم وهي عن طريق‬

icon BottomNavigationBar‫شكل ال‬

lable BottomNavigationBar‫كل عنصر في ال‬

BottomNavigationBarItem
BottomNavigationBarItem ‫عبارة عن‬
lable‫ خاصة ب‬icon ‫ و‬lable ‫يتكون‬
‫‪51‬‬

‫‪Bottom Navigation Bar in Flutter:‬‬

‫‪pageController‬‬
‫متغير من نوع ‪ PageController‬قمنا بتعريفه في ص ‪ 49‬واستخدمناه في‪ pageView‬من ضمن‬
‫الميثود الموجود فيه هي الميثود )‪ jumpToPage(pageNumber‬من خالل هذه الميثود نمرر لها‬
‫رقم الصفحة لالنتقال اليها‬
‫دالة تنفذ عن الضغط على ‪ item‬الموجود في‪onTap(){}BottomNavigationBar‬‬
‫‪currentPageIndex = value‬‬
‫قمنا بتعريفه في صفحة ‪currentPageIndex 49‬‬
‫هو رقم الصفحة الحالية ‪value‬‬
‫نستخدمها لكي يتم التغيير ;))((‪setState‬‬

‫عند النقر على أول واجهة تكون األيقونة الخاصة بها باللون األزرق ويمكن تغيير هذا اللون وكذلك\‬
‫الحال في األيقونات األخرى‬

You might also like