הסברים והערות שלי לעצמי כהכנה להוראה. בהמשך יתכן שאדגיש סרטונים חשובים יותר ופחות
פרק 0 התקנה. והערה כללית
- הדגמה על מחשב תלמיד.
כיוון שאסף הוסיף פרק 1 התקנה, נוצר מצב שבתפריט שלו, פרק 1 המקורי ממוספר 2, וכך גם כל הפרקים ממוספרים בתפריט בספרור מוגדל ב-1. ההתייחסות שלי היא לספרור המקורי כך שמי שמוריד “ספרי קורס” יגיע למספרים הנכונים.
פרק 1. תכנות בסיסי
פירוט והערות
- מתחילים ישר לתוך ה-xml
- הערה כללית - תראו דברים שימושיים שעושים גם כיום. הרבה פעמים ה- איך עושים לא יהיה אקטואלי
- חסרה התייחסות לכך שיש אזור JAVA ואזור xml
1.1 Linear Layout - דוגמאות לפקודות עיצוב ב-xml
- orientation=”vertical”
- layout_width=”match_parent” VS “wrap_content”
- קצת צבעים לדבר על RGB
- והגדרת id לכל אלמנט כדי שנוכל להתחבר
- מתן שם לטקסס שהid שלו יתחיל ב- tvSomething
- והכפתור יתחיל בתחילית btnSomething
1.2,1.3 הדגמה בצד הJAVA של הכרזה על כפתורים
- סרטון קצרצר שמראה הכרזה. ניתן להיות עם חפיפה בין שם העצם ל-id
btnAdd = findViewById(R.id.theIdAutoCompletes)// לשים לב שאנחנו לא צריכים שום קאסטינג כיום
1.4,5 תגובה ללחיצה על הכפתור
example 1
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
int counter;
TextView tvDisplay;
Button btnPlus;
Button btnMinus;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
// XML - התחברות לכפתורים מה
btnPlus= findViewById(R.id.btnPlus);
btnMinus= findViewById(R.id.btnMinus);
tvDisplay= findViewById(R.id.tvDisplay);
btnPlus.setOnClickListener(this);
btnMinus.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v==btnPlus) {
counter++;
} else if (v==btnMinus) {
counter--;
}
tvDisplay.setText("Total Points " + counter);
}
}
simpler way כאשר אין צורך לטפל באופן אחיד במספר כפתורים שונים
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// XML - התחברות לכפתורים מה
etFname = findViewById(R.id.etFname);
etLname = findViewById(R.id.etLname);
btnSave = findViewById(R.id.btnSave);
tvDisplay = findViewById(R.id.tvDisplay);
btnSave.setOnClickListener(v -> {
tvDisplay.setText(etFname.getText() + " " + etLname.getText());
});
}
מה מותר ואסור למחוק
הסבר פקודות ב-onCreate - מה אפשר למחוק ומתי
super.onCreate(savedInstanceState)super.onCreate(savedInstanceState);מה זה עושה: קורא לבנאי של המחלקה האב (
AppCompatActivity)האם אפשר למחוק? ❌ לעולם לא!
- זו פקודה חובה בכל Activity
- בלעדיה האפליקציה תקרוס
- חייבת להיות הפקודה הראשונה ב-
onCreate
EdgeToEdge.enable(this)EdgeToEdge.enable(this);מה זה עושה: מפעיל תצוגה מקצה לקצה (edge-to-edge) - התוכן עולה מתחת לסטטוס בר ולניווט בר
האם אפשר למחוק? ✅ כן, בהחלט
- זו תכונה חדשה שנוספה ב-Android Studio החדש (2023+)
- אם תמחק אותה, האפליקציה תעבוד רגיל עם המרווחים הסטנדרטיים
- מתי למחוק: כשאתה לא רוצה עיצוב edge-to-edge, או כשזה מסבך לך את העיצוב
setContentView(R.layout.activity_main)setContentView(R.layout.activity_main);מה זה עושה: טוען את קובץ ה-XML של הממשק (layout) למסך
האם אפשר למחוק? ❌ לא!
- בלעדיה לא יהיה לך ממשק משתמש
- כל ה-
findViewByIdיחזירוnull - חובה לכל Activity עם ממשק גרפי
(...)ViewCompat.setOnApplyWindowInsetsListenerViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets; });מה זה עושה: מוסיף padding כדי שהתוכן לא יוסתר על ידי הסטטוס בר/ניווט בר במצב edge-to-edge
האם אפשר למחוק? ✅ כן, במקרים רבים
מתי למחוק:
- אם מחקת את
EdgeToEdge.enable(this)- אז אין צורך בזה - אם הוספת padding ידני ב-XML (בתוך ה-ConstraintLayout עם
android:padding="16dp") - אם התוכן שלך לא צריך להימנע מהסטטוס בר
מתי לשמור:
- אם את.ה רוצה edge-to-edge אבל לא רוצה שהתוכן יוסתר
- אם העיצוב שלך דינמי ומשתנה
- אם מחקת את
סיכום מהיר
| מותר למחוק? | מתי למחוק |
|---|---|
| אף פעם ❌ | super.onCreate() |
| ❌ אף פעם (אלא אם אין UI) | setContentView() |
| אופציונלי ✅ edge-to-edge | EdgeToEdge.enable() |
| אופציונלי ✅ EdgeToEdge או יש padding ב-XML | ViewCompat.setOnApplyWindowInsetsListener() |
1.6 הדגמת תכונות נוספות של פקדים (ש6 דוגמא 2 חלק 1)
- העתקה של תמונה ל- drawable
- background set to the @drawable
- hint
- layout_margin
- guideline percent
preferred constraintlayout with guidelines
```xml <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/tvDisplay" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/btnPlus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="56dp" android:text="Button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tvDisplay" /> <Button android:id="@+id/btnMinus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="56dp" android:text="Button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/btnPlus" /> </androidx.constraintlayout.widget.ConstraintLayout> ``` - preferred approach for event:
preferred setOnClickListener
```java public class MainActivity extends AppCompatActivity //implements View.OnClickListener { TextView tvDisplay; EditText etFname; EditText etLname; Button btnSave; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets; }); etFname = findViewById(R.id.etFname); etLname = findViewById(R.id.etLname); btnSave = findViewById(R.id.btnSave); tvDisplay = findViewById(R.id.tvDisplay); //btnSave.setOnClickListener(this); btnSave.setOnClickListener(v -> { tvDisplay.setText(etFname.getText() + " " + etLname.getText()); }); } // @Override // public void onClick(View v) { // if(v==btnSave) { // tvDisplay.setText(etFname.getText() + " " + etLname.getText()); // } // } } ``` Advantages of lambdas: ✅ More concise - no need to implement interface or override method ✅ Clearer intent - the action is right where the listener is set ✅ No if-statement checks needed ✅ Modern Java/Android standard ✅ Easier to read and maintain
פרק 2.סוגי האזנות בתכנות לאנדרואיד
פירוט והערות
בפרק, אסף מדגים כיצד ליצור האזנות לפקדים מסוגים שונים. בכל הדוגמאות הטכניקה שלו היא כתיבת פונקציה מלאה, והרפרנס ששולחים הוא this שהוא Activity כלומר:
- במחלקה של ה-
Activityמכריזים על מימוש ממשקonClickListener(או באופן כלליonWhateverListener) myObject.setOnSomethingListener(this);- ממשים פונקציה מלאה ובתוכה שואלים אם העצם שקיבלנו הוא כך וכך, ופועלים בהתאם.
ברוב המקרים לא נזדקק למימוש מהסוג הזה.
- ה-
Activityלא יוגדר ככזה שממש את ה-listener - נשתמש בפונקציות אנונימיות, ונגדיר את התגובה לאירוע ישירות בתוך הקריאה ל-
listenerכפי שמודגם כאן:
טיפול ישיר באירועים באמצעות פונקציות אנונימיות (Lambda Expressions)
פונקציות Lambda בטיפול באירועים
הצורה v -> { ... } היא דרך מקוצרת לכתיבת פונקציה אנונימית (Lambda Expression) שמטפלת באירועים. (פונקציה אנונימית היא פונקציה עם תוכן אך ללא שם)
במקום לכתוב:
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// קוד
}
});
כותבים בצורה מקוצרת:
btnSave.setOnClickListener(v -> {
tvDisplay.setText(etFname.getText() + " " + etLname.getText());
});
דוגמה עם מספר פרמטרים - ListView
כאשר הפונקציה מקבלת יותר מפרמטר אחד, נשתמש בסוגריים סביב כל הפרמטרים:
ListView listView = findViewById(R.id.listView);
TextView tvSelected = findViewById(R.id.tvSelected);
// פונקציה אנונימית עם 4 פרמטרים
listView.setOnItemClickListener((parent, view, position, id) -> {
// parent - the AdapterView (הרשימה עצמה)
// view - the View של הפריט שנלחץ
// position - מיקום הפריט ברשימה (0, 1, 2...)
// id - מזהה ייחודי של הפריט
String item = (String) parent.getItemAtPosition(position);
tvSelected.setText("בחרת: " + item + " במיקום " + position);
});
דוגמה עם מספר פונקציה ומספר פרמטרים - SeekBar
כאשר רוצים לקבל יותר מפרמטר אחד, נשתמש בסוגריים:
SeekBar seekBar = findViewById(R.id.seekBar);
TextView tvProgress = findViewById(R.id.tvProgress);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// פרמטר 1: seekBar - הפקד עצמו
// פרמטר 2: progress - הערך הנוכחי
// פרמטר 3: fromUser - האם השינוי בוצע על ידי המשתמש
tvProgress.setText("ערך: " + progress);
if (fromUser) {
// פעולה רק אם המשתמש שינה את הערך
seekBar.setBackgroundColor(Color.BLUE);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
tvProgress.setText("מתחיל לגעת...");
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
tvProgress.setText("סיים לגעת");
}
});
הסבר על הפרמטרים:
- seekBar - הפקד SeekBar עצמו
- progress - מספר שלם המייצג את המיקום הנוכחי (0-100 או לפי הגדרת max)
- fromUser - ערך boolean שמציין אם המשתמש הזיז את הסרגל או שהשינוי בוצע בקוד