Dart לפיתוח אפליקציות Flutter - ממש על קצה המזלג
שפת Dart מזכירה Kotlin וגם קצת JavaScript. זו השפה באמצעותה כותבים אפליקציות Flutter שניתן לפרוס בקלות על אנדרואיד, אייפון ויישומי דסקטופ. במדריך זה ריכזתי כמה דברים מאוד בסיסיים שחשוב לדעת כיצד לעשות ב-Dart לפני שמתחילים לפתח אפליקציות Flutter.
ניתן להתאמן על שימוש בשפה בלי להתקין שום דבר על המחשב. כל מה שצריך הוא לגלוש לאתר: https://dartpad.dev, ולהקליד את הפקודות במדריך.
בשפת Dart הפונקציה main() מאתחלת את ביצוע הקוד. לדוגמה:
main () {
print("Hello World!");
}
- חשוב לסיים כל שורת קוד בנקודה פסיק ;
התוצאה:
Hello World!
נתחיל שורה של הערה בשני קווים נטויים.
// main() is responsible for
// executing all the code
main () {
print("Hello World!");
}
- ללא הפונקציה main() הקוד לא יצא אל הפועל. בהתאם, את כל הקוד במדריך צריך לבצע בתוכה אלא אם צויין אחרת.
אנחנו יכולים להגדיר משתנים באמצעות מילת המפתח var:
var greeting = "Hello";
- כש-Dart יכול להסיק בעצמו את הסוג נעדיף להגדיר את המשתנה באמצעות var אבל לא תמיד זה המצב.
Dart היא שפה שאוהבת לעבוד עם סוגים types לכן אם Dart לא יכול להסיק בעצמו את סוג המשתנה כי הערך יוצב בהמשך נגדיר את סוג המשתנה כדי לעזור לקומפיילר לאתר שגיאות בקוד כמה שיותר מוקדם.
ישנם כמה סוגים בסיסיים של משתנים שחשוב להכיר ב-Dart:
מחרוזות מגדירים כ- String
String greeting;
בוליאנים הם bool:
bool isEarthPerson;
אחר כך אנחנו צריכים להציב משתנים בהתאם לסוג:
greeting = "Hello earth person";
isEarthPerson = true;
אנחנו יכולים להציב ערך בזמן ההגדרה של המשתנה ואז אין צורך לציין את הסוג:
var greeting = "Hello earth person";
var isEarthPerson = true;
נשתמש בסוג משתנה int כדי לציין מספר שלם:
int n;
n = 3;
הסוג double מציין מספר עשרוני:
double d;
d = 3.14;
שימוש בתנאים (בוליאנים)
בוליאנים מאפשרים לתוכנה לעשות משהו אחד אם מתקיים התנאי ואחר אם אינו מתקיים. הסוג בוליאני יכול לקבל אחד משני ערכים: true או false.
var greeting = "Hello earth person";
var isEarthPerson = true;
var visitedMars = true;
// run code if both variables
// are true
if (isEarthPerson && visitedMars) {
print ("Kudos!!");
// run the code if only the first
// variable is true
} else if (isEarthPerson && !visitedMars) {
print (greeting);
// default code to run
} else {
print ("Not earth person. Maybe a Martian.");
}
התוצאה:
Kudos!!
- נציין את האופרטור and באמצעות &&.
- את האופרטור or נציין באמצעות 2 צינורות ||.
- כדי להפוך את הערך של בוליאני מ-true ל- false והפוך נקדים את ה-bang operator ! לשם המשתנה.
Ternary operator
אפשר לכתוב תנאים באופן קומפקטי יותר על ידי שימוש ב Ternary operator. לדוגמה, אפשר לכתוב תנאי שמברר האם משתנה הוא מספר זוגי כך:
var myInt= 8;
String evenness = '';
if (myInt % 2 == 0) {
evenness = "$myInt is even";
} else {
evenness = "$myInt is odd";
}
print(evenness);
- הבעיה היא שתחביר זה הוא ארוך מדי.
את התנאי אפשר לכווץ לשורה אחת:
String evenness = myInt % 2 == 0? "$myInt is even" : "$myInt is odd";
- מה שבא משמאל לסימן השאלה הוא התנאי.
- מימין לסימן השאלה נכתוב את חלופות הקוד לביצוע.
- בין החלופות. מה שמופיע משמאל לנקודתיים הוא הקוד לביצוע במקרה של קיום התנאי. מימין לנקודתיים ישנו הקוד לביצוע במקרה בו התנאי אינו מתקיים.
שימוש בלולאות
נשתמש בלולאת for:
main () {
int start = 1;
int end = 5;
for(int i = start ; i <= end; i++ ) {
print(i);
}
}
התוצאה:
1 2 3 4 5
אפשר גם להשתמש בלולאת while:
var bigNumber = 1000;
while (bigNumber > 5) {
print(bigNumber);
bigNumber = bigNumber ~/ 10;
}
התוצאה:
1000 100 10
- האופרטור ~/ הוא floor divide והוא מעגל מספר עשרוני למספר השלם הנמוך הקרוב ביותר.
רשימה list
רשימה יכולה להכיל אוסף של משתנים. לדוגמה, רשימה של מחרוזות ששמה cars:
List<String> cars = [];
נוסיף פריטים לרשימה באמצעות הפקודה add():
main () {
List<String> cars = [];
cars.add("Tesla");
cars.add("Audi");
cars.add("BMW");
print(cars);
}
התוצאה:
[Tesla, Audi, BMW]
להסרת פריטים נשתמש בפקודה-remove():
main () {
List<String> cars = [];
cars.add("Tesla");
cars.add("Audi");
cars.add("BMW");
cars.remove("Audi");
print(cars);
}
התוצאה:
[Tesla, BMW]
נעבור בלולאה על כל אחד מהפריטים ברשימה:
main () {
List cars = ["Tesla", "Audi", "BMW"];
for (int i=0;i<cars.length;i++){
print(cars[i]);
}
}
התוצאה:
Tesla Audi BMW
פונקציות
כשאנחנו מגדירים פונקציה נגדיר את סוג המשתנים שהיא מחזירה. אם פונקציה לא מחזירה דבר היא תהיה void:
main () {
void greet(){
print("Hello world!");
}
greet();
}
התוצאה:
Hello world!
אם פונקציה מחזירה מחרוזת נגדיר כ-String:
main () {
String greet(){
return "Hello Mishu";
}
print(greet());
}
התוצאה:
Hello Mishu!
אם פונקציה מקבלת פרמטרים אז חשוב להגדיר את סוג המשתנים שהיא רשאית לקבל:
main () {
String greet(String person){
return "Hello $person";
}
print(greet("Mishu"));
}
התוצאה:
Hello Mishu!
אנחנו יכולים להפוך את הפרמטרים של הפונקציה לאופציונליים על ידי כך שנעטוף את הפרמטרים בסוגריים מרובעים ונוסיף ערך ברירת מחדל:
String greetOptional(String bless, [String person = '']){
return "$bless $person";
}
print(greetOptional("Helloo", "Moshe"));
print(greetOptional("Helloo"));
התוצאה:
Helloo Moshe Helloo
ישנה דרך חלופית שבה פונקציה יכולה לקבל פרמטר אופציונלי.
כשלא מעבירים ערך לפרמטר הערך שהוא מקבל הוא null באופן אוטומטי. אנחנו יכולים להגדיר את סוג המשתנה כאופציונלי על ידי הוספת סימן שאלה לימין הסוג, והצבת ערך ברירת מחדל:
String greetOptional(String bless, [String? person]){
if (person == null) {
return "$bless mishoo";
}
return "$bless $person";
}
- הנושא של טיפול בערכי null הוא חשוב ביותר כשעובדים עם Dart. נא לשים לב ולהתנהג בהתאם!
עד עכשיו העברנו לפונקציה פרמטרים מסוג positional בהם חיוני להקפיד על סדר ההזנה. כדי להעביר פרמטרים מסוג named parameters נשתמש בסוגריים מסולסלים:
String greetNamed({required String person, String bless ='hello'}){
return "$bless $person";
}
print(greetNamed(person: 'moshe'));
print(greetNamed(bless: 'Hola', person: 'amigo'));
פרמטרים מסוג named parameters:
- אינם דורשים הקפדה על סדר ההזנה (בניגוד ל-positional(.
- כשמגדירים אותם צריך להגדיר ערך ברירת מחדל או להפוך להכרחיים באמצעות ה-key word required.
פונקציות חץ arrow functions
תחביר קומפקטי יותר לכתיבת פונקציות הוא באמצעות שימוש בפונקציות חץ שעושות פעולה ומחזירות ערך והכול בשורה אחת של קוד.
במקום:
String greetNamed({required String person}) {
return "Hello, $person";
}
אנחנו יכולים לכתוב:
String greetNamed({required String person}) => "Hello, $person";
נריץ את הפונקציה:
print(greetNamed(person: 'moshe'));
התוצאה:
Hello, moshe
- במקום 3 שורות אנו משתמשים בתחביר קומפקטי של שורה 1.
- אחרי הסוגריים שמקבלים את הפרמטרים אנחנו כותבים fat arrow ואחריו מגיע גוף הפונקציה.
- לא משתמשים ב-return
פונקציות לעבודה עם רשימות
נגדיר רשימה:
List<String> cars = [
"Audi",
"Tesla",
"BMW",
"Volvo",
"Mercedes",
];
נשתמש בפונקציה contains() כדי לברר האם פריט קיים ברשימה. לדוגמה:
cars.contains("Tesla");
נשלב את זה ב-Ternary expression:
var car = "Tesla";
print(cars.contains(car) ? "We have a $car" : "No such car");
התוצאה:
We have a Tesla
נשתמש ב-join() כדי להפוך מערך למחרוזת. לדוגמה נהפוך את הרשימה cars למחוזת ונחבר בין הפריטים במחרוזת שתיווצר באמצעות פסיקים:
String strCars = cars.join(",");
print(strCars);
התוצאה:
Audi,Tesla,BMW,Volvo,Mercedes
הפונקציה split() עושה הפוך. לוקחת מחרוזת ומפצלת לרשימה (מערך). לדוגמה:
strCars.split(",")
התוצאה:
[Audi, Tesla, BMW, Volvo, Mercedes]
- מערך
הפונקציה forEach() מקבלת מערך, ומבצעת פעולה על כל פריט.
בדוגמה הבאה נעבור עם לולאת forEach על כל פריט ברשימת המכוניות ונדפיס במידה ואורך המחרוזת הוא 5:
cars.forEach((item){
if (item.length == 5) {
print(item);
}
});
התוצאה:
Tesla Volvo
שימוש בפונקציה where יאפשר לנו לסנן רשימה כדי לקבל את הפריטים שמעניינים אותנו:
cars.where((item){
return (item.length == 5);
});
- כל איטרציה מחזירה בוליאני: true, false.
- מאוד חשוב להשתמש ב-return אחרת כל איטרציה תחזיר null, ונקבל שגיאה.
הפונקציה where() מחזירה Iterable אותו נהפוך לרשימה באמצעות toList():
List<String> myCars = cars.where((item){
return (item.length == 5);
}).toList();
print(myCars);
התוצאה:
[Tesla, Volvo]
אפשר לכתוב יותר בקצרה באמצעות פונקציית חץ:
List<String> myCars = cars.where((item) => item.length == 5).toList();
אם אנחנו מעוניינים בפריט הראשון ברשימה שעונה על תנאי נשתמש בפונקציה firstWhere():
String myCar = cars.firstWhere((item){
return (item.length == 5);
});
print(myCar);
התוצאה:
Tesla
כדי לבצע פעולה על כל אחד מפריטי הרשימה ולהחזיר רשימה חדשה נשתמש בפונקציה map().
לדוגמה:
List<String> myCars = cars.map((item){
return "$item has a sunroof";
}).toList();
print(myCars);
התוצאה היא רשימה חדשה עם פריטים שעברו מודיפיקציה:
[Audi has a sunroof, Tesla has a sunroof, BMW has a sunroof, Volvo has a sunroof, Mercedes has a sunroof]
כשעובדים עם הפונקציה map() חשוב לשים לב לשני דברים:
- מאוד חשוב להשתמש ב-return אחרת כל איטרציה תחזיר null.
- הפונקציה מחזירה Iterable אותו נהפוך לרשימה באמצעות toList().
אפשר לקרוא לפונקציה בכל איטרציה:
String withSunroof(String name) {
return "$name has a sunroof";
}
List<String> myCars = cars.map((item){
return withSunroof(item);
}).toList();
את אותה תוצאה נשיג בתחביר מקוצר באמצעות פונקציית חץ:
List<String> myCars = cars.map((item) => withSunroof(item)).toList();
עבודה עם מחלקות ותכנות מונחה עצמים
מחלקות, קלאסים, הם כלי קיבול הכורך יחדיו קוד לטיפול בנושא מסוים. לדוגמה, למכונית יכול להיות שם דגם וגג שמש אז נגדיר מחלקה בשם Car שתכיל את המשתנים name ו-sunRoof:
class Car {
String name;
bool hasSunroof;
Car(
this.name,
this.hasSunroof
);
}
- את ערכי המשתנים נעביר לקלאס בזמן שניצור ממנו אובייקט דרך הקונסטרקטור ששמו כשם הקלאס.
אנחנו יכולים לייצר קלאס שהקונסטרקטור שלו מקבל פרמטרים שיש להם שם:
class Car {
String name;
bool hasSunroof;
// Named parameters in the constructor
// The parameters have to be required or need to have a default value
Car({required this.name, this.hasSunroof = false});
}
נקים מהקלאס אובייקטים באופן הבא:
final car1 = Car(name: 'Tesla');
final car2 = Car(name: 'BMW', hasSunroof: true);
כדי להפוך תכונה לפרטית נוסיף קו תחתון לפני שמה, לדוגמה: bool _hasSunroof;:
class Car {
String name;
bool _hasSunroof;
// ...
}
כדי לקבל יותר אפשרויות בהגדרת ובשליפת הנתונים נשתמש בפונקציות setter ו-getter.
class Car {
String name;
bool _hasSunroof;
Car(
this.name,
this._hasSunroof
);
bool get hasSunroof {
return _hasSunroof;
}
set hasSunroof(bool val) {
_hasSunroof = val;
}
}
את הקלאס נקפיד להגדיר מחוץ לפונקציה main אבל ביצוע הקוד יהיה בתוך main:
main () {
var myCar1 = Car("Tesla", false);
// get the property
print(myCar1.hasSunroof);
// set the property
myCar1.hasSunroof = true;
print(myCar1.hasSunroof);
}
- את המשתנה myCar1 הגדרתי var במקום Car מפני ש- Dart יכול להבחין בעצמו שהמשתנה ניזון מפונקציה שמחזירה אובייקט מסוג מסוים. יכולתי גם לציין את סוג המשתנה Car זו לא שגיאה אבל פחות נכון מבחינה תכנותית.
התוצאה:
false true
רשימות של אובייקטים
כשעובדים עם Flutter משתמשים הרבה ברשימות של אובייקטים.
נגדיר מחלקה Car שיש לה 2 תכונות - name ו-country:
class Car {
String name;
String country;
Car({required this.name, required this.country});
}
ניצור רשימת מכוניות שיישמו את הקלאס Car:
List<Car> cars = [
Car(name: 'Jaguar', country: 'UK'),
Car(name: 'BMW', country: 'Germany'),
Car(name: 'Mercedes', country: 'Germany'),
Car(name: 'Sabra', country: 'Israel'),
];
נשתמש במתודה where() כדי להישאר עם מודלים תוצרת גרמניה.
Iterable<Car> germanCars = cars.where((item) => item.country == "Germany");
- קיבלנו Iterable.
נהפוך את ה-Iterable לרשימה, ואז נעבור עליו באמצעות לולאת forEach() ונדפיס כל פריט ברשימה:
germanCars.toList().forEach((item) => print(item.name));
התוצאה:
BMW Mercedes
אם כבר אנחנו עוסקים ברשימות אז ננצל את זה כדי ללמוד כיצד לסדר רשימות לפי הסדר באמצעות המתודה sort().
נעביר למתודה בתור פרמטר פונקציה משווה compareTo().
לדוגמה, נסדר את המכוניות לפי סדר א"ב של השמות:
// sort cars according to their name
cars.sort((a, b) => a.name.compareTo(b.name));
נעזר בלולאת forEach() כדי להדפיס את פרטי הרשימה המסודרת:
// print the sorted cars
cars.toList().forEach((item) => print(item.name));
התוצאה:
BMW Jaguar Mercedes Sabra
כדי לקבל את הרשימה בסדר הפוך נשתמש במילת המפתח sorted:
// sort in reverse order
cars.reversed.toList().forEach((item) => print(item.name));
התוצאה:
Sabra Mercedes Jaguar BMW
למדריכים נוספים בסדרת ה-Flutter
שימוש ב-provider באפליקציית Flutter
הקמת אפליקציית Flutter פשוטה על גבי מסד נתונים Firebase
אהבתם? לא אהבתם? דרגו!
0 הצבעות, ממוצע 0 מתוך 5 כוכבים
המדריכים באתר עוסקים בנושאי תכנות ופיתוח אישי. הקוד שמוצג משמש להדגמה ולצרכי לימוד. התוכן והקוד המוצגים באתר נבדקו בקפידה ונמצאו תקינים. אבל ייתכן ששימוש במערכות שונות, דוגמת דפדפן או מערכת הפעלה שונה ולאור השינויים הטכנולוגיים התכופים בעולם שבו אנו חיים יגרום לתוצאות שונות מהמצופה. בכל מקרה, אין בעל האתר נושא באחריות לכל שיבוש או שימוש לא אחראי בתכנים הלימודיים באתר.
למרות האמור לעיל, ומתוך רצון טוב, אם נתקלת בקשיים ביישום הקוד באתר מפאת מה שנראה לך כשגיאה או כחוסר עקביות נא להשאיר תגובה עם פירוט הבעיה באזור התגובות בתחתית המדריכים. זה יכול לעזור למשתמשים אחרים שנתקלו באותה בעיה ואם אני רואה שהבעיה עקרונית אני עשוי לערוך התאמה במדריך או להסיר אותו כדי להימנע מהטעיית הציבור.
שימו לב! הסקריפטים במדריכים מיועדים למטרות לימוד בלבד. כשאתם עובדים על הפרויקטים שלכם אתם צריכים להשתמש בספריות וסביבות פיתוח מוכחות, מהירות ובטוחות.
המשתמש באתר צריך להיות מודע לכך שאם וכאשר הוא מפתח קוד בשביל פרויקט הוא חייב לשים לב ולהשתמש בסביבת הפיתוח המתאימה ביותר, הבטוחה ביותר, היעילה ביותר וכמובן שהוא צריך לבדוק את הקוד בהיבטים של יעילות ואבטחה. מי אמר שלהיות מפתח זו עבודה קלה ?
השימוש שלך באתר מהווה ראייה להסכמתך עם הכללים והתקנות שנוסחו בהסכם תנאי השימוש.