גרפיקה בסיסית


פורסם ב 31/05/2010 ע"י האקדמיה לפיתוח לאנדרואיד

אנדי שבוע טוב חובבי אנדרואיד יקרים וברוכים השבים לאקדמיה!

אחרי שעשינו מעבר קליל על נושאים בתיכנות בסיסי, הגיע הזמן להתחיל ולממש אפליקציות ישר על מערכת ההפעלה אנדרואיד. למען אילו ממכם שעדיין לא צברו מספיק ידע ונסיון בתיכנות בסיסי ובמונחים בסיסיים בג'אווה, אנו נשלב מידי פעם בשיעורים שלנו השלמות קטנות בנושאים הרלוונטיים שיכלו לעזור לכם להשלים את הפער.

קצת על השיעורים הבאים

במהלך השיעורים הבאים נלמד אותכם אודות מונחי יסוד במערכת ההפעלה אנדרואיד וניתן דוגמאות כיצד לממש אותם. את הנושאים הנלמדים בשיעורים אלו ניתן לממש בצורות רבות ויתכן והצורה בה בחרתי לא תתאים לכל סוג מימוש, אך חשוב לזכור שמטרתה היא להקנות לכם ידע בסיסי ולהעניק לכם את הכלים כדי להמשיך לחקור וללמוד על הנושא בעצמכם. גם הצורה שבה אשתמש בתיכנות מונחה עצמים לא תהיה האופטימלית ביותר והיא נועדה כדי לפשט את הנושאים. יחד עם זאת, אני מזמין את כולכם להציע צורות טובות יותר ונכונות יותר באשכול השיעור בפורום הפיתוח לאנדרואיד שלנו או בכל אשכול אחר בפורום הפיתוח בפורטל.

הנושאים שנלמד במהלך השיעורים הקרובים ישמשו אותנו כדי ליצור משחק פינג פונג לאנדרואיד, כאשר אני מזמין אתכם להרחיב אותו, לשכלל אותו, לשנות אותו וכאמור, גם לפרסם אותו בפורום הפיתוח לאנדרואיד.

על השיעור של היום

בשיעור הזה נדבר נטעם על קצה המזלג גרפיקה בסיסית במערכת ההפעלה אנדרואיד. מטרת השיעור היום היא ללמד אתכם אודות הסיפריות והפקודות המשמשות להצגת גרפיקה במכשיר (או האמולטור) שלכם ואת הארכיטקטורה שמומלץ לממש כדי להציג אלמנטים גרפיים רבים על מסך אחד.

אז לפני הכל, בואו נתחיל מהבסיס.

רכיבי בסיס באנדרואיד

במערכת ההפעלה אנדרואיד ישנם ארבעה רכיבים בסיסיים שניתן לממש כדי לפתח אפליקציות. הרכיבים הללו הם בעצם מחלקות לכל דבר, אשר בפועל קוראות ומתקשרות אחת עם השניה כדי ליצור את האפליקציה. ואלו הם סוגי הרכיבים הקיימים:

Activities (או "פעילויות" בתירגום חופשי), המהווה כל דבר בעל ממשק משתמש ויזואלי. Activity יכולה להיות מסך המציג את הודעות האס.אם.אס במכשיר, בעוד ש Activity אחר יכולה להיות מסך לכתיבה או מענה על אס.אם.אס קיים. אנחנו נתמקד ביצירה והפעלה של Activities במהלך כל הקורס הנוכחי.

Services (או "שירותים"), מהווה כל תוכנית שרצה ברקע ואין לה ממשק משתמש. דוגמא ל- Service יכולה להיות אפליקציה שבודקת ברקע האם יש דואר חדש, או שמשמיעה מוסיקה ברקע. הפעלה של Service יכולה להעשות מתוך Activity מסויים לדוגמא, ממשק הנגן מכיל כפתור Play שמפעיל Service שמשמיע מוסיקה ברקע.

Broadcast receivers (או "מקבלי שידור") הם שדרי מערכת גלובליים המעדכנים כי משהו במערכת השנתה, כמו לדוגמא שהמשתמש צילם תמונה או שהמכשיר חובר לבטריה וכדומה. באנדרואיד ישנם מספר רב של שירותי עידכון קיימים שניתן להתחבר אליהם ולהגיב אליהם בהתאם.

Content Provider (או "ספקי תוכן") הם רכיבי מידע אשר ניתן לשתף בין מספר אפליקציות שונות. לדוגמא, המידע של ספר הטלפונים שלכם במכשיר או הודעות האס.אם.אס עצמם שמורות כל אחת בתוך "ספק תוכן" שכזה ובאפשרותנו לכתוב אפליקציה שקוראת מהם. באותה צורה ניתן ליצור גם ספק תוכן משלנו, להזין לתוכו מידע ולאפשר לאחרים לקרוא אותו (או לכתוב, באם איפשרנו את הדבר).

ארבעת הרכיבים הללו הם הבסיסיים ביותר במערכת ההפעלה וממנה בעצם מורכב הכל (טוב, תלוי מה מגדירים כ"הכל"). שימו לב שרכיב אחד יכול לקרוא לרכיב אחר ללא תלות בין הסוגים. לדוגמא, יכולה להיות לנו פעילות המכילה תפריט, אשר כל אפשרות בתפריט קוראת לפעילות אחרת המציגה מסך אחר ובעוד שיציאה מהתוכנית יכולה לקרוא לשירות (Service) שירוץ ברקע ויבצע דברים שונים. דוגמא נוספת יכולה להיות שירות עדכון (Broadcast Service) שמעדכן מתי הגיע הודעת אס.אם.אס חדשה וברגע שהודעה כזאת הגיעה, הוא מפעיל Activity שמציג אותה.

כל פרויקט אנדרואיד חייב להתחיל ע"י יצירה של אחד מארבעת הרכיבים הללו. כפי שציינתי מקודם, במהלך הקורס הנוכחי אנו נתרכז במימוש רכיבי Activities בלבד.

יצירת Activity חדש
האמת היא שבעבר, כבר יצא לנו ליצור Activity, עוד בשיעור אודות התקנת סביבת הפיתוח. בואו נבצע זאת שוב וניצור לנו את פרויקט הפינג פונג שלנו.

היכנסו לתוך Eclipse וביחרו File -> New -> Project ובמסך שיפתח ביחרו ב Android Project תחת Android

יצירת פרויקט חדש לאנדרואיד

כעת ניפתח לכם מסך יצירת הפרויקט. הזינו את המסך כפי שמופיע בתמונה הבאה:

יצירת פרויקט PingPong באנדרואיד

הסבר על השדות:
Project Name: שם הפרויקט החדש שלנו. אנחנו בחרנו ב PingPong.
Build Target: גירסת האנדרואיד הקטנה ביותר עליה נירצה להריץ את הפרויקט. אנחנו בחרנו את 1.6.
Application Name: שם האפליקציה שלנו בתוך. הזינו iAndroid Ping Pong.
Package Name: שם ה"חבילה" הראשית שלנו (על חבילות דיברנו בשיעור ד'). הזינו iAndroid.pingPong.
Create Activity: שימו לב, כאן אנו ניתקלים לראשונה במונח הבסיסי של הפעילות ונשאלים האם ליצור אחת כחלק מהפרויקט. סמנו את התיבה והזינו את שם הפעילות המרכזית שלנו PingPong.

שימו לב תלמידים יקרים שלא סתם אנדי בחר בגירסא 1.6. גירסאות חדשות יותר מכילות אומנם אפשרויות חדשות ושיפורים רבים לערכת הפיתוח, אך המשמעות היא שמי שמותקנת לו גירסא ישנה יותר על המכשיר, לא יוכל להפעיל את האפליקציה, וחבל. לפיכך עדיף להתפשר ולבחור גירסא נמוכה יותר, בכדי לאפשר לקהל יותר רחב להינות מהאפליקציה שלכם.
אנדינקודה חשובה מאד פרופסור!
יש לקחת נושאים אלו בחשבון בכל אפליקציה שאתם יוצרים.

לאחר שסיימתם להזין את המידע, ליחצו על Finish.

ובכך נוצר לכם פרויקט הפינג פונג החדש. אם תיכנסו לעץ בצד שמאל לתוך PingPong/src/ תוכלו לראות את החבילה שיצרתם ובתוכה את קובץ ה- Activity שלכם PingPong.java.
הקליקו עליו ותוכלו לראות את המחלקה PingPong אשר יורשת את המחלקה Activity

ה Activity שנוצר למשחק הפינג פונג החדש שלנו באנדרואיד

Views

טוב, אז יש לנו Activity ואנחנו יכולים להפעיל אותו. בשלב הבא מה שנירצה זה להציג דברים בתוך ה Activity הזה ולשם כך אנחנו משתמשים במחלקה View.

View היא בעצם מחלקת בסיס שממנה נגזרים כל הרכיבים הגראפיים באנדראויד (כלומר, הרכיבים הגראפיים יורשים אותה ומרחיבים אותה בהתאם לצרכים שלהם). רכיב גראפי יכול להיות כפתור, תיבת טקסט או אפילו מסך שלם שמציג בתוכו כפתורים ותיבות טקסט.
מחלקת הבסיס של View מכילה מתודה בשם onDraw אשר תופעל בכל פעם שמישהו רוצה לצייר את ה View שלנו.
בדרך כלל רכיבים גרפיים מסויימים מורכבים מתתי רכיבים גרפיים, לדוגמא מסך המציג משחק פינג פונג הוא View ראשי אשר מפעיל View אחר שנקרא "כדור". לפיכך הצורה שבה מממשים Viewים היא בצורה של היררכיה, כאשר כל View קורא ל- View שמתחתיו.

הדיאגרמה הבאה מדגימה את ההיררכיה הבסיסית של ה- Viewים במשחק הפינג פונג שלנו:

היררכיית ה- Viewים במשחק הפינג פונג

בראש יש לנו את PingPongView אשר משמש בתור ה View הראשי שלנו, כלומר כל המשחק בעצם מוצג בתוכו.
מתחתיו יש לנו את BallView האחראי להצגת הכדור של המשחק ואת PaddleView האחראי לצייר את המחבט.

PingPongView הוא ה View הראשון, שיקרא ע"י ה Activity, והוא יהיה בעצם אחראי לקרוא ל BallView ו PaddleView, כדי לצייר אותם.

לפני שניצור את כל ה- Viewים האלה, להלן סקירה קצרה על מערכת הקורדינטות במסך המכשיר שלנו:

מערכת הקורדינטות

מסך מכשיר האנדרואיד שלנו, כמו מסך המחשב, מורכב בעצם מסידרה של נקודות ציבעוניות (פיקסלים) מהם מורכבת התמונה שלנו. לדוגמא, מסך מכשיר הנקסוס יכול להכיל 480 פיקסלים לרוחב ו 800 פיקסלים לגובה.

כאשר אנחנו רוצים לצייר משהו על המסך (אם זה פיקסל בודד או תמונה מקובץ), אנחנו צריכים להגיד למחשב באיזה פיקסל רוחבי (X) ובאיזה פיקסל אופקי (Y) אנחנו רוצים לצייר אותה. לדוגמא, אם היינו רוצים נותנים למחשב פקודה לצייר את רובוט האנדרואיד בנקודה x=1,y=1 אז הוא היה מצוייר כך:

אנדרואיד במיקום 1,1 על מכשיר הנקסוס

אם היינו רוצים לצייר אותו בנקודה x=100, y=100, אז הוא היה מצוייר כך:

אנדרואיד במיקום 100,100 על מכשיר הנקסוס

למכשירים שונים יש מסכים שונים ורזולוציות שונות. אנחנו נתמודד עם הנושא הזה בהמשך, אך בשלב זה חשוב רק להסביר איך בנוי המסך ואין אומרים למחשב איפה לצייר דברים שונים.

אז בואו נחזור לה- Viewים.

יצירת PingPongView

כפי שנאמר עד כה, PingPongView הינו ה- View הראשי שיצייר את כל הרכיבים האחרים.
אז בואו וניצור אותו. בתוך Eclipse, ליחצו מקש ימני של העכבר על החבילה iAndroid.pingPong (בצד שמאל של המסך) וביחרו New -> Class.
במסך שניפתח לכם, הזינו את הנתונים בצורה הבאה:

יצירת מחלקת PingPongView

הסבר על השדות:
Source folder: הסיפריה בה ניצור את הקובץ החדש. שדה זה אמור להיות מלא אוטומטית.
Package: החבילה אליה משתייכת המחלקה החדשה. גם שדה זה אמור להיות מלא אוטומטית ולהכיל את החבילה עליה הקלקנו מקש ימני עם העבר.
Name: שם המחלקה שאנחנו רוצים ליצור. רישמו PingPongView.
SuperClass: המחלקה אותה אנחנו יורשים ומרחיבים. כאמור, אנחנו מרחיבים את מחלקת View שנמצאת בתוך החבילה android.view. ביחרו ב- Browse, חפשו אותה בפנים וביחרו בה.

ליחצו על Finish.

נוצרה לנו מחלקה חדשה בשם PingPongView אשר יורשת ומרחיבה את מחלקת View.
שימו לב כי יש המחשב מתריע לנו על שגיאה

שגיאה לאחר יצירת המחלקה PingPongView

הסיבה לשגיאה היא כי מחלקת View, ממנה אנחנו יורשים, מכילה בנאי המקבל פרמטר. בשיעור השני אודות תיכנות מונחה עצמים, הזכרנו בחטף כי כאשר אנו יורשים מחלקה אשר מכילה בנאי המקבל פרמטר, חובה עלינו ליצור בנאי זהה, המקבל גם הוא פרמטר.
Eclipse בא לעזרתנו במקרה הזה ומאפשר לנו להגדיר אוטומטית את הבנאי החסר. ליחצו עם העכבר ליחצה אחת ויחידה על סימן ה- X בעורך הקוד (במרכז) ויפתח לכם תפריט עם רשימת תיקונים אפשריים. ביחרו "Add constructor PingPongView(Context).

כעת יצרנו את ה- View הראשון שלנו. כפי שכתבתי למעלה, מחלקת הבסיס של View מכילה מתודה בשם onDraw אשר ניקראת אוטומטית ברגע שהגיע הזמן לצייר את המסך. אנחנו נרצה "לתפוס שליטה" על כל נושא הציור ולהיות אחראיים בעצמנו על ציור הרכיבים השונים. יחד עם זאת, כרגע עדיין אין לנו מה לצייר… לפיכך רק נממש את המתודה onDraw אבל לא ניכתוב בה כלום.

הקוד של PingPongView.java צריך להיראות כך:

[sourcecode language="java"]
package iAndroid.pingPong;

import android.content.Context;
import android.graphics.Canvas;
import android.view.View;

public class PingPongView extends View {

public PingPongView(Context context) {
super(context);
}

@Override
public void onDraw(Canvas canvas) {
// nothing here yet…
}

}
[/sourcecode]

מחלקות הכדור

ישנם שתי מחלקות המייצגות את הכדור שלנו:

Ball: מחלקה שמייצגת את התכונות וההתנהגויות הלוגיות של הכדור שלנו, לדוגמא מה המיקום הנוכחי של הכדור ומתודה שמזיזה את הכדור צעד אחד.
BallView: מחלקה היורשת את View ויודעת לקבל עצם מסוג Ball ולצייר אותו (כלומר היא מכילה תכונה מסוג Ball ומתודה onDraw שמציירת אותו).

את אלו מכם שלא ותיקים בתיכנות מונחה עצמים, יכולה ההפרדה הזאת לבלבל מעט. הרי תיאורטית אפשר לשים את Ball ואת BallView תחת מחלקה אחת, לא?
אז כן, זה בהחלט אפשרי, אבל לוגית זה לא בטוח הכי נכון. ההפרדה בתיכנות מונחה עצמים מאד חשובה ואני ממליץ לכם לחזור שוב על שיעורי הבסיס שהבאנו בשבועות האחרונים כדי להיזכר בה.

המחלקה Ball

בואו ניצור את המחלקה Ball. בתוך Eclipse, ליחצו מקש ימני של העבר על החבילה iAndroid.pingPong (בצד שמאל של המסך) וביחרו New -> Class.
במסך שניפתח לכם, הזינו את הנתונים בצורה הבאה:

יצירת המחלקה Ball למשחק הפינג פונג

הסבר על השדות:
Source folder: הסיפריה בה ניצור את הקובץ החדש. שדה אמור להיות ממולא אוטומטית.
Package: החבילה אליה משתייכת המחלקה החדשה. גם שדה זה אמור להיות ממולא אוטומטית ולהכיל את החבילה עליה הקלקנו מקש ימני עם העבר.
Name: שם המחלקה שאנחנו רוצים ליצור. רישמו Ball.
SuperClass: המחלקה ממנה אנחנו יורשים. במקרה הזה, מחלקת Ball אינה יורשת מאף מחלקה אחרת ולכן השאירו שדה זה כמו שהוא.

ליחצו על Finish.

נוצרה לנו מחלקה חדשה בשם Ball.
איזה תכונות ומתודות נוסיף לכדור שלנו? בשלב זה נוסיף לכדור תכונה שמתארת את מיקומו על המסך ונוסיף שני מתודות שמחזירות את המיקום הזה.
בנוסף, ניצור בנאי שבו נגדיר את המיקום ההתחלתי של הכדור.

להלן הקוד של Ball.java:

[sourcecode language="java"]
package iAndroid.pingPong;

public class Ball {
private int x;
private int y;

// Receive the start position of the ball and
public Ball (int startX, int startY)
{
this.x = startX;
this.y = startY;
}

// Return the ball horizental position
public int getX()
{
return this.x;
}

// Return the ball vertical position
public int getY()
{
return this.y;
}

}
[/sourcecode]

הסבר קצר על הקוד:
שורות 4-5: הגדרה של המשתנים הפרטיים x ו- y שיחזיקו את מיקום הכדור על המסך.
שורות 8-12: הגדרת הבנאי של המחלקה, המקבל את המיקום ההתחלתי של x ושל y כפרמטרים.
שורות 15-18: מתודה המחזירה את x.
שורות 15-18: מתודה המחזירה את y.

המחלקה BallView

כעת ניצור את המחלקה BallView שיודעת לצייר את הכדור שלנו. המחלקה BallView שלנו תקבל אובייקט מסוג Ball בבנאי ותצייר אותו במיקום בו הוא נימצא בכל פעם שתיקרא המתודה onDraw שלה.
כדי לצייר את הכדור אנו נישתמש במחלקת Paint של אנדרואיד, שמאפשרת לנו להגדיר איך לצייר צורות שונות. בשיעור זה לא ניכנס לעומק של מחלקת Paint אלה רק נסביר בכלליות מה רשמנו לגביה.

להלן הקוד של המחלקה BallView.java:

[sourcecode language="java"]
package iAndroid.pingPong;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;

public class BallView extends View {
private Ball theBall;

private Paint ballPaint;

public BallView(Context context, Ball newBall) {
super(context);

this.theBall = newBall;
}

private Paint getBallPaint()
{
if (ballPaint == null)
{
ballPaint = new Paint();
ballPaint.setStrokeWidth(2);
ballPaint.setColor(Color.WHITE);
}

return ballPaint;
}

@Override
public void onDraw(Canvas canvas) {
// Drawing the ball
canvas.drawCircle(theBall.getX(), theBall.getY(), 15, getBallPaint());
}

}
[/sourcecode]

נסביר קצת אודות הקוד:
שורה 9: הגדרה של מחלקה בשם BallView היורשת ממחלקת View.
שורה 10: הגדרת משתנה פרטי מסוג Ball בשם theBall שיכיל את הכדור שנצייר.
שורה 12: הגדרת משתנה פרטי מסוג Paint בשם ballPaint, בו נישתמש כדי לייצר את הכדור.
שורה 14: הגדרה של בנאי המחלקה, המקבל כפרמטר את הכדור אותו המחלקה תצייר.
שורה 15: קריאה לבנאי האב של המחלקה (הבנאי של View אותו ירשנו).
שורה 17: שמירת הכדור שהועבר כפרמטר לבנאי בתוך המשתנה הפרטי theBall.
שורות 20 עד 30: הגדרת מתודה פרטית היוצרת לנו ומחזירה עצם מסוג Paint בו נישתמש כדי לצייר את הכדור. שימו לב כי המתודה בנויה בצורה חכמה שיוצרת לנו את העצם רק פעם אחת ולא כל פעם מחדש.
שורה 33: הגדרת המתודה onDraw לה ניקרא ברגע שנירצה לצייר משהו על המסך.
שורה 35: ציור הכדור על המסך, כלומר, ציור של עיגול עם רדיוס של 15 פיקסלים. (טוב, לא סתם קוראים למתודה הזאת drawCircle 🙂 ).

שימו לב שבשורה 35, אנו משתמשים ב getX ו getY שבתוך theBall כדי לקבל את מיקום הכדור. דוגמא זאת מדגישה לנו את ההפרדה שעשינו בין הלוגיקה של הכדור (המחלקה Ball) לבין הלוגיקה של ציור הכדור (המחלקה BallView).

הרחבה נוספת של PingPongView

כעת, אחרי שהגדרנו את מחלקת BallView, אנחנו צריכים לדאוג שהמתודה onDraw שלה תיקרא ע"י המתודה onDraw של PingPongView (זוכרים את סירטוט ההיררכיה של ה Viewים שהצגנו מקודם?).
אני שוב מזכיר לכם, שהקריאה ל onDraw הראשי (של PingPongView) מבוצעת אוטומטית ע"י ה- Activity, אך כל מה שמתחת ל- PingPongView (שזה במקרה שלנו, BallView), חייב להיעשות באופן יזום ע"י PingPongView.

לשם כך אנחנו צריכים להרחיב את מחלקת PingPongView כדי שתוכל לקבל עצם מסוג BallView, ולאחר מכן לשנות את המתודה onDraw שלה כדי שתיקרא ל- onDraw של BallView.
להלן הקוד החדש של PingPongView.java:

[sourcecode language="java"]
package iAndroid.pingPong;

import android.content.Context;
import android.graphics.Canvas;
import android.view.View;

public class PingPongView extends View {
private BallView ballV;

public PingPongView(Context context) {
super(context);
}

public void setBallView(BallView view)
{
this.ballV = view;
}

@Override
public void onDraw(Canvas canvas) {
// Drawing the ball
this.ballV.onDraw(canvas);
}

}
[/sourcecode]

בואו נעבור על הקוד שהוספנו:

שורה 8: הגדרת משתנה פרטי מסוג BallView בשם ballV
שורות 14 עד 17: הגדרת מתודה בשם setBallView אשר מקבלת עצם מסוג BallView ושומרת אותו בתוך ballV הפרטי.
שורה 22: הוספת קריאה יזומה ל- onDraw של ballV.

מחברים את כל החלקים

הגיע הזמן לחבר את כל החלקים יחדיו. מה שאנחנו צריכים זה להגדיר את הכדור, להגדיר את ה- View של המשחק, את ה- View של הכדור ולבסוף, לתת ל- Activity שלנו את ה- View הראשי.

להלן קטע הקוד המעודכן של ה- Activity שלנו, PingPong.java:

[sourcecode language="java"]
package iAndroid.pingPong;

import android.app.Activity;
import android.os.Bundle;

public class PingPong extends Activity {
private PingPongView gameView;
private Ball gameBall;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Creating the ball
gameBall = new Ball(100, 100);

// Creating the ball view, and giving it the gameBall as a parameter
BallView ballView = new BallView(this, gameBall);

// Creating the game view
this.gameView = new PingPongView(this);

// Give the gameView our ballView.
gameView.setBallView(ballView);

// Setting the gameView as the main view for the PingPong activity.
setContentView(gameView);
}

}
[/sourcecode]

הסבר על התוספות לקטע קוד זה:
שורה 07: הגדרת משתנה פרטי מסוג PingPongView בשם gameView, שיהווה את ה- View הראשי של ה- Activity.
שורה 08: הגדרה של משתנה פרטי מסוג Ball בשם gameBall, שישמש בתור הכדור של המשחק שלנו.
שורה 16: יצירה של עצם חדש מסוג Ball, וקביעת המיקום הראשוני שלו במסך בנקודה 100,100.
שורה 19: הגדרה של View מסוג BallView, בו נשתמש כדי להציג את הכדור (את הכדור שיוצג העברנו לו כפרמטר ביצירה שלו).
שורה 22: יצירת ה- View הראשי של המשחק, מסוג PingPongView.
שורה 25: הוספת ה- View של הכדור לתוך PingPongView, כדי שיוכל לצייר אותו.
שורה 28: לבסוף, הגדרת ה- View הראשי של ה- Activity עצמה, ע"י קריאה ל setContentView והעברת PingPongView כפרמטר.

שימו לב לגבי שורה 28, שלפני השינוי שלנו, קטע קוד זה היה היה כתוב כך:

[sourcecode language="java"]setContentView(R.layout.main);[/sourcecode]

R.layout.main הוא View ברירת מחדל שמוגדר בתוך ה- Resource של הפרויקט (הוא זה שמכיל בעצם את המשפט Hello World שמקבלים כאשר מפעילים אפליקציה חדשה).
אנחנו החלפנו את ה- View הזה ב- View שלנו (gameView), כדי שיהיה מוצג במקומו.
על Resource-ים ו- Layout-ים אנחנו נדבר בהרחבה בשיעורים הבאים שלנו.

ומה עכשיו?
עכשיו נותר רק להריץ את התוכנה ולראות מה מתקבל.

הצגת הכדור הפינג פונג, על האמולטור של אנדרואיד

אז יש לנו כדור, איזה יופי!
כן כן, אני יודע שזה רק עיגול לבן שמצוייר על המסך, אבל גם את רומא לא בנו ביום אחד.
בשיעור הבא אנחנו נלמד להזיז אותו על המסך ובהמשך אף נחליף אותו בתמונה אמיתית של כדור. מה שחשוב הוא לקחת את החומר שנלמד בשיעור הזה ולהתנסות איתו. שנו את גודל הכדור, צרו מספר כדורים שונים, הציגו אותם במקומות שונים ותנו להם צבעים שונים.

לסיכום השיעור, הייתי רוצה לתת לכם תלמידים יקרים שיעורי בית. צרו מחלקה חדשה שתייצג את מחבט הכדור והעניקו לה את התכונות המתאימות. לאחר מכן צרו לה View שיודע להציג אותה ולבסוף, הציגו את המחבט על המסך. טיפ קטן. המחבט יהיה ככל הנראה מלבני ובשביל לצייר אותו, נסו להשתמש בפקודה canvas.drawRect והעבירו לה את Paint, כפי שעשינו במחלקה BallView.

אנדיכרגיל, אחלה תרגיל פרופסור!
אני מזמין אותכם לפרסם את התשובות לתרגיל באשכול השיעור בפורום הפיתוח לאנדרואיד, וגם להעיר הערות, לשאול שאלות, לפתח ובעיקר לחלוק את הכל עם הקהילה.

עד כאן להיום. להתראות בשיעור הבא.

Share

האקדמיה לפיתוח לאנדרואיד

בואו ללמוד לפתח לאנדרואיד! אתם בטח זוכרים אותי בתור Andy מהבלוג הישן!

25 Comments

  1. אופק
    01/06/2010 בשעה 05:10

    תודה!!

  2. guest
    01/06/2010 בשעה 19:19

    הערה קטנה בקשר לאנוטציה
    @Override
    לעיתים האנוטציות האלו עושות בעיות (אם אני זוכר נכון, כאשר מקמפלים עם ג'אוה 1.5 ולא 1.6, ועושים override למתודה של interface), ולכן יש מי שנוהג לוותר עליהן.
    כדאי לדעת למקרה של בעיות קומפילציה ו/או אם ה-eclipses לא אוהב את זה.

    1. הפרופסור
      11/06/2010 בשעה 16:54

      תודה למשתמש guest, על ההערה.

      בשפת java, בניגוד לשפות אחרות כגון C# או C++
      אין צורך בשימוש ב- keyword מיוחד כדי לציין שמתודה דורסת מתודה אחרת שהוגדרה במחלקת האב.
      אך אליה וקוץ בה – ללא שימוש ב- Keyword ייעודי ניתן בקלות יחסית לשכוח שהמתודה דורסת מתודה אחרת, ואת המשמעויות הכרוכות,
      ובדיוק לצורך זה באה לענות האנוטציה Override@.
      לאחר ששמנו את האנוטציה לפני הגדרת המתודה,
      במידה ושינינו בטעות את חתימתה של המתודה המודברת – והיא אינה דורסת יותר מתודה אחרת – נקבל אזהרה מהקומפיילר.

      כפי שציין המשתמש guest,
      המשמעות של האונטציה Override@ השתנתה מ- Java 1.5 ל- Java 1.6,
      כאשר ב- 1.5 ניתן היה להתשמש בה עבור מתודה הדורסת מתודה שהוגדרה במחלקת האב בלבד,
      בעוד שב- 1.6 השימוש הורחב והוא כולל מעתה בנוסף גם מימוש של מתודה שהוגדרה ב- interface.

  3. שמוליק
    01/06/2010 בשעה 22:38

    תודה על ההשקעה!

  4. אורי
    02/06/2010 בשעה 13:50

    אחלה מדריך אהבתי, אבל השיעורי בית כלים יש מצב שיהיו יותר קשים?

    1. הפרופסור
      02/06/2010 בשעה 21:43

      בסדר גמור, בשיעור הבא אתן לכם שתי אתגרים, אחד יותר קליל והשני יותר מאתגר.

  5. רועי
    19/06/2010 בשעה 13:17

    מי שרוצה AntiAlaising לכדור יכול לעשות זאת ע"י תפיסה של הPaint שמקבלים מ BallPaint למשתנה מסוג Paint
    ואז מריצים עליו את הפונקציה setAntiAlias (עם הערך TRUE)
    דוגמה:
    Paint p = getBallPaint();
    p.setAntiAlias(true);
    canvas.drawCircle(theBall.getX(), theBall.getY(), 15, p);

    ואז נקבל כדור עם קצוות מוחלקים(פשוט נעים יותר לעין) 🙂
    רועי

  6. אנדי
    19/06/2010 בשעה 14:45

    תודה על הטיפ רועי 🙂

  7. גבי
    21/07/2010 בשעה 18:55

    היי אנדי,
    מהו בעצם משתמש מסוג Context ומדוע הבנאי של מחלקת View מקבל אותו?

  8. אנדי
    22/07/2010 בשעה 15:28

    היי גבי,

    שאלה מצויינת!

    Context הינה מחלקה המכילה מידע שימושי רב אודות הסביבה שבה האפליקציה רצה.
    פלטפורמת אנדרואיד דואגת לאכלס אובייקט מטיפוס המחלקה (יותר מדוייק מאחת המחלקות שיורשות ממנה, שכן Context היא מחלקה אבסטרקטית) עם כל המידע הרלוונטי, ולהעביר אותו לבנאי של המחלקה View, על מנת שזה יוכל לעשות בו שימוש.
    מידע זה כולל למשל את ההרשאות של האפליקציה, מידע על ה- package-ים שממנה היא מורכבת, מידע על המשאבים (Resources) שלה, גודל המסך שעליו היא רצה ועוד ועוד..
    פעמים רבות מידע זה שימושי מאוד בתוך הבנאי, ולכן הוא מועבר ע"י הפלטפורמה.

  9. בנצי
    22/08/2010 בשעה 10:49

    אחלה של אתר !! יישר כוח!! הסברים מצויינים

  10. ארז
    03/09/2010 בשעה 11:59

    הי,
    משום מה יש לי בעיה כשאני מנסה ליצור את המחלקה של ה-view. כשאני לוחץ על superclass כדי לבחור android.view.view, מופיע לי שם רק פריט אחד – Object – java.lang.
    מה עשיתי לא נכון?

    תודה!

    1. אנדי
      08/09/2010 בשעה 22:01

      הממ… מוזר ביותר.
      זה נראה כאילו ה- SDK של אנדרואיד לא מותקן לך.

      האם פעלת לפי הוראות ההתקנה בשיעורים הקודמים?

  11. ארז
    10/09/2010 בשעה 08:00

    כן. הכל מותקן לי על שני מחשבים – אחד עם windows והשני עם mac, בשניהם זה לא מופיע. אם אני כותב את זה ידנית אז זה עובד והכל תקין… זה סתם מרגיז.

  12. דוד
    19/11/2010 בשעה 08:35

    בניתי את הכל כמו שמופיע כאן, אבל כל פעם שאני מנסה להריץ את התוכנית הוא פשוט מריץ לי את התוכנה שיצרתי בSDK Manager. כלומר סתם נפתח האמולטור ולא מופיע שם שום כדור.
    חוץ מזה כל הכבוד על האתר!

  13. בוב
    20/01/2011 בשעה 14:58

    כיצד ניתן להתמודד עם חריגות (EXCEPTIONSׁׂׂ) תוך שמירה על חוקי הסביבה,
    אני שואל זאת מכיוון שכל שימוש ב-TRY/CATCH או שימוש בהרחבה של מחלקת חריגה מובנית מונעת הרצה של האפליקציה ומחזירה הודעת קריסה באמולטור.

    זה אתר נפלא!!!
    תודה,

  14. בני מרגלית
    29/01/2011 בשעה 06:32

    כל הכבוד יפה מאוד.
    הסברים מצויינים.
    כיף ךראות שיש חומרים טובים בעברית.
    תודה רבה

  15. דני
    28/03/2011 בשעה 16:43

    היי,עשיתי את המדריך במדוק עם גירסה אחרונה של ECLIPSE וזה משאיר לי הודעה על המסך השחור:Android_
    התקנתי כבר פעמים את כל הסביבה ועדיין אותו דבר

  16. דני
    28/03/2011 בשעה 16:44

    סליחה זה עובד – לא חיכיתי מספיק זמן

  17. zantebi
    20/04/2011 בשעה 03:20

    כל הכבוד , דוגמאות והסברים מצויינים

  18. amstel
    26/04/2011 בשעה 22:05

    שלום, משום מה כל פעם שאני מנסה להריץ את התכנית,
    היא עולה באמולטור אבל נסגרת כל פעם מחדש.
    הודעות השגיאה היא:
    "The application iAndroid Ping Pong (process iAndroid.pingPong) has stopped unexepectedly. Please try again."
    מה יכולה להיות הבעיה?
    בדקתי גם שאני מנסה להפעיל לאותה גירסה כמו של האמולטר.
    תודה על העזרה.

  19. viva_d
    17/08/2011 בשעה 02:58

    איפה המורה ללשון? ב"מחלקות הכדור", 'ישנן' ולא 'ישנם'.

    היה כדאי להסביר על context בשיעור עצמו ולא רק כתשובה.

    כל הכבוד על היוזמה, הביצוע וההשקעה !!!

  20. orsharon
    08/09/2011 בשעה 09:48

    אין לי פונקציה מובנת שנקראת oncreat בתכל'ס אפשר לעשות את אותם דברים בקונסטרקטור לא?

  21. דורון
    09/10/2011 בשעה 13:19

    תודה על האתר הניפלא.
    בזן הרצת אפליקציית ה Ping Pong האמולטר נפתח וכאשר אני לוחץ על menu רואים את שת התוכנית iandroid Ping Pong
    אבל לא רואים כדור.
    התוכנית מתקמפלת ורצה ללא הודעות שגיאה, עברתי על ההתקנות כולל ה SDM למישהו יש רעיון ?
    כמו שמישהו כבר רשם, כאשר לוחצים על superclass יש רק מחלקה אחת לבחור java.lang.object לא ניתן לבחור android.view.View אבל כשרושמים זה מתקבל

  22. boaz0n@walla.com
    02/11/2011 בשעה 14:09

    היי, ממש אחלה מדריכים, חלק אני מבין וחלק יקח קצת זמן

    מישהו מוכן להגיד לי
    למה לא מופיע לי ה Package Explorer?

    תודה!

השאר תגובה