הוספת מפה לאפליקציית iOS‏ (Objective-C)

1. לפני שתתחיל

מופשט

ב-codelab הזה תלמדו את כל מה שצריך כדי להתחיל להשתמש בפלטפורמה של מפות Google לבניית אפליקציות ל-iOS ב-Objective-C. במדריך הזה תלמדו את כל היסודות, החל מהגדרה ועד לטעינה של Maps SDK ל-iOS, הצגת המפה הראשונה, עבודה עם סמנים וקיבוץ סמנים, ציור על המפה וטיפול באינטראקציה של המשתמשים.

מה תפַתחו

342520482a888519.png

ב-codelab הזה תיצרו אפליקציית iOS שתבצע את הפעולות הבאות:

  • טעינה של Maps SDK ל-iOS ושל Maps SDK ל-iOS Utility Library
  • הצגת מפה עם מרכוז בסידני, אוסטרליה
  • תצוגה של סמנים מותאמים אישית ל-100 נקודות מסביב לסידני
  • הטמעה של מקבץ סמנים
  • מאפשר אינטראקציה עם המשתמש שמרכזת מחדש ומציירת עיגול במפה כשלוחצים על סמן

מה תלמדו

  • תחילת העבודה עם הפלטפורמה של מפות Google
  • טעינה של Maps SDK ל-iOS ושל Google Maps SDK ל-iOS Utility Library
  • טעינת מפה
  • שימוש בסמנים, בסמנים מותאמים אישית ובקיבוץ סמנים
  • עבודה עם מערכת האירועים של Maps SDK ל-iOS כדי לספק אינטראקציה עם המשתמש
  • שליטה במפה באופן פרוגרמטי
  • ציור על המפה

דרישות מוקדמות

כדי להשלים את ה-codelab הזה, צריך להכיר את הפריטים הבאים. אם אתם כבר יודעים איך לעבוד עם Google Maps Platform, אתם יכולים לדלג אל ה-codelab.

מוצרים נדרשים בפלטפורמה של מפות Google

ב-codelab הזה תשתמשו במוצרים הבאים של הפלטפורמה של מפות Google:

  • SDK של מפות ל-iOS
  • Google Maps SDK for iOS Utility Library

תחילת העבודה עם הפלטפורמה של מפות Google

אם לא השתמשתם בפלטפורמה של מפות Google בעבר, תוכלו לעיין במדריך לתחילת העבודה עם הפלטפורמה של מפות Google או לצפות בפלייליסט לתחילת העבודה עם הפלטפורמה של מפות Google כדי לבצע את השלבים הבאים:

  1. יוצרים חשבון לחיוב.
  2. יוצרים פרויקט.
  3. מפעילים את ממשקי ה-API וערכות ה-SDK של הפלטפורמה של מפות Google (שמופיעים בקטע הקודם).
  4. יוצרים מפתח API.

דרישות נוספות ל-Codelab הזה

כדי להשלים את ה-codelab הזה, תצטרכו את החשבונות, השירותים והכלים הבאים:

  • חשבון ב-Google Cloud Platform עם חיוב מופעל
  • מפתח API של הפלטפורמה של מפות Google עם SDK של מפות ל-iOS מופעל
  • ידע בסיסי ב-Objective-C
  • ‫Xcode 12.0 עם SDK יעד בגרסה 12.0 ואילך

2. להגדרה

בשלב ההפעלה שבהמשך, תצטרכו להפעיל את Maps SDK ל-iOS.

הגדרת הפלטפורמה של מפות Google

אם עדיין אין לכם חשבון ב-Google Cloud Platform ופרויקט עם חיוב מופעל, תוכלו לעיין במדריך תחילת העבודה עם הפלטפורמה של מפות Google כדי ליצור חשבון לחיוב ופרויקט.

  1. בCloud Console, לוחצים על התפריט הנפתח של הפרויקט ובוחרים את הפרויקט שבו רוצים להשתמש ב-codelab הזה.

  1. מפעילים ב-Google Cloud Marketplace את ממשקי ה-API וערכות ה-SDK של הפלטפורמה של מפות Google שנדרשים ל-codelab הזה. כדי לעשות זאת, פועלים לפי השלבים בסרטון הזה או בתיעוד הזה.
  2. יוצרים מפתח API בדף Credentials במסוף Cloud. אפשר לפעול לפי השלבים שמפורטים בסרטון הזה או בתיעוד הזה. כל הבקשות אל הפלטפורמה של מפות Google מחייבות מפתח API.

Project Starter Template Setup

לפני שמתחילים את ה-codelab הזה, צריך להוריד את תבנית הפרויקט למתחילים ואת קוד הפתרון המלא:

  1. אפשר להוריד או ליצור עותק (fork) של מאגר GitHub של ה-codelab הזה בכתובת https://github.com/googlecodelabs/maps-platform-101-objc.

הפרויקט StarterApp נמצא בספרייה /starter וכולל את מבנה הקבצים הבסיסי שנדרש כדי להשלים את ה-codelab. כל מה שצריך לעבודה נמצא בספרייה /starter/StarterApp.

כדי לראות את קוד הפתרון המלא, אפשר לבצע את שלבי ההגדרה שלמעלה ולצפות בפתרון בספרייה /solution/SolutionApp.

3. התקנה של Maps SDK ל-iOS

השלב הראשון בשימוש ב-Maps SDK ל-iOS הוא התקנת התלויות הנדרשות. התהליך הזה כולל שני שלבים: התקנת Maps SDK ל-iOS וספריית כלי השירות של Maps SDK ל-iOS ממנהל התלות של Cocoapods, ומתן מפתח ה-API ל-SDK.

  1. מוסיפים את Maps SDK ל-iOS ואת Maps SDK ל-iOS Utility Library אל Podfile.

ב-codelab הזה תשתמשו גם ב-SDK של מפות ל-iOS, שמספק את כל הפונקציונליות העיקרית של מפות Google, וגם בספריית כלי השירות של מפות ל-iOS, שמספקת מגוון כלי שירות להעשרת המפה, כולל אשכולות של סמנים.

כדי להתחיל, פותחים את הקובץ Pods > Podfile ב-Xcode (או בעורך הטקסט המועדף) ומעדכנים אותו כך שיכלול את התלות של Maps SDK ל-iOS ושל Utility Library בקטע use_frameworks!:

pod 'GoogleMaps'
pod 'Google-Maps-iOS-Utils'
  1. מתקינים את Maps SDK ל-iOS ואת Maps SDK ל-iOS Utility Library pods.

כדי להתקין את יחסי התלות, מריצים את הפקודה pod install בספרייה /starter משורת הפקודה. ‫Cocoapods יוריד באופן אוטומטי את התלויות וגם ייצור את StarterApp.xcworkspace. 3. אחרי שמתקינים את התלויות, פותחים את StarterApp.xcworkspace ב-Xcode ומריצים את האפליקציה בסימולטור של אייפון על ידי לחיצה על Command+R. אם הכול מוגדר בצורה נכונה, הסימולטור יופעל ויוצג מסך שחור. אל דאגה, עדיין לא יצרת כלום, אז זה צפוי! 4. מייבאים את ה-SDK ב-AppDelegate.h.

אחרי שמתקינים את יחסי התלות, צריך לספק את מפתח ה-API ל-SDK. השלב הראשון הוא לייבא את Maps SDK ל-iOS כתלות על ידי הוספת השורה הבאה מתחת ל#import "AppDelegate.h" הצהרת הייבוא:

@import GoogleMaps;
  1. מתחת להצהרת הייבוא של iOS SDK, מצהירים על קבוע NSString עם הערך שמוגדר למפתח ה-API:
static NSString *const kMapsAPIKey = @"YOUR API KEY";
  1. מעבירים את מפתח ה-API אל iOS SDK על ידי קריאה ל-provideAPIKey ב-GMSServices ב-application: didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GMSServices provideAPIKey:kMapsAPIKey];
  return YES;
}

קובץ AppDelegate.m המעודכן אמור להיראות כך:

#import "AppDelegate.h"
@import GoogleMaps;

static NSString *const kMapsAPIKey = @"YOUR API KEY";

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GMSServices provideAPIKey:kMapsAPIKey];
  return YES;
}
@end

התג Podfile אמור להיראות כך:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '11.0'

target 'StarterApp' do
  use_frameworks!

pod 'GoogleMaps', '5.1.0.0'
pod 'Google-Maps-iOS-Utils', '3.4.0'

end

אחרי שהתקנתם את התלויות וסיפקתם את מפתח ה-API, אתם יכולים להתחיל לבצע קריאות ל-Maps SDK ל-iOS.

4. הצגת מפה

הגיע הזמן להציג את המפה הראשונה!

החלק הנפוץ ביותר ב-Maps SDK ל-iOS הוא המחלקה GMSMapView, שמספקת רבות מהשיטות שמאפשרות ליצור מופעים של מפות ולבצע בהם מניפולציות. כך עושים זאת.

  1. פתיחת ViewController.m.

כאן תבצעו את כל העבודה שנותרה ב-codelab הזה. תראו שאירועי מחזור החיים של בקר התצוגה loadView ו-viewDidLoad כבר מוגדרים בשבילכם. 2. כדי לייבא את Maps SDK ל-iOS, מוסיפים את השורה הבאה בחלק העליון של הקובץ:

@import GoogleMaps;
  1. מצהירים על משתנה מופע ViewController כדי לאחסן את GMSMapView.

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

@implementation ViewController {
  GMSMapView *_mapView;
}
  1. ב-loadView, יוצרים מופע של GMSCameraPosition.

GMSCameraPosition מגדיר את המיקום שיהיה במרכז המפה ואת רמת הזום שתוצג. הקוד הזה קורא לשיטה cameraWithLatitude:longitude:zoom: כדי למרכז את המפה בסידני, אוסטרליה, בקו רוחב של ‎-33.86 וקו אורך של ‎151.20, עם רמת זום של 12:

GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.86 longitude:151.20 zoom:12];
  1. ב-loadView, יוצרים מופע של GMSMapView כדי ליצור מופע של המפה.

כדי ליצור מופע חדש של מפה, קוראים ל-mapWithFrame:camera:. שימו לב שהמסגרת מוגדרת ל-CGRectZero, שהוא משתנה גלובלי מספריית CGGeometry של iOS שמציין מסגרת עם רוחב 0, גובה 0, שממוקמת במיקום (0,0) בתוך בקר התצוגה. המצלמה מוגדרת למיקום המצלמה שיצרתם.

כדי להציג את המפה בפועל, צריך להגדיר את תצוגת הבסיס של בקר התצוגה ל-_mapview, וכך המפה תוצג במסך מלא.

_mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.view = _mapView;
  1. מגדירים את GMSMapViewDelegate לבקר התצוגה.

אחרי ההטמעה, נציג התצוגה של המפה מאפשר לכם לטפל באירועים מאינטראקציות של משתמשים במופע GMSMapView, שתצטרכו בשלבים הבאים.

קודם צריך לעדכן את הממשק של ViewController כך שיתאים לפרוטוקול של GMSMapViewDelegate:

@interface ViewController ()<GMSMapViewDelegate>

לאחר מכן, מוסיפים את הפקודה הבאה כדי להגדיר את GMSMapViewDelegate לערך ViewController.

_mapView.delegate = self;

עכשיו טוענים מחדש את האפליקציה בסימולטור iOS (Command+R), והמפה אמורה להופיע.

2e6ebac422323aa6.png

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

קובץ ViewController.m אמור להיראות עכשיו כך:

#import "ViewController.h"
#import "LocationGenerator.h"
@import GoogleMaps;

@interface ViewController ()<GMSMapViewDelegate>
@end

@implementation ViewController {
  GMSMapView *_mapView;
}

- (void)loadView {
  [super loadView];
  GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.86 longitude:151.20 zoom:12];
  _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
  self.view = _mapView;
  _mapView.delegate = self;
}

5. עיצוב מפות מבוסס-ענן (אופציונלי)

אתם יכולים להתאים אישית את הסגנון של המפה באמצעות עיצוב מפות מבוסס-ענן.

יצירת מזהה מפה

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

  1. יוצרים מזהה מפה.
  2. משייכים מזהה מפה לסגנון מפה.

הוספת מזהה המפה לאפליקציה

כדי להשתמש במזהה המפה שיצרתם בשלב הקודם, פותחים את הקובץ ViewController.m ובתוך ה-method‏ loadView יוצרים אובייקט GMSMapID ומזינים בו את מזהה המפה. לאחר מכן, משנים את יצירת המופע של GMSMapView על ידי ציון האובייקט GMSMapID כפרמטר.

ViewController.m

- (void)loadView {
    GMSMapID *mapID = [[GMSMapID alloc] initWithIdentifier:@"YOUR_MAP_ID"];
    _mapView = [GMSMapView mapWithFrame:CGRectZero mapID:mapID camera:camera];
    // ...
}

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

6. הוספת סמנים למפה

יש הרבה דברים שמפתחים עושים עם Maps SDK ל-iOS, אבל הצבת סמנים במפה היא ללא ספק הפעולה הפופולרית ביותר. סמנים מאפשרים להציג נקודות ספציפיות במפה, והם רכיב נפוץ בממשק המשתמש לטיפול באינטראקציה של המשתמשים. אם השתמשתם בעבר במפות Google, אתם כנראה מכירים את סמן ברירת המחדל, שנראה כך:

590815267846f166.png

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

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

  1. מגדירים אובייקט CLLocationCoordinate2D.

CLLocationCoordinate2D הוא מבנה שזמין בספריית CoreLocation של iOS, שמגדיר מיקום גיאוגרפי בקו רוחב ובקו אורך מסוימים. כדי להתחיל ליצור את הסמן הראשון, מגדירים אובייקט CLLocationCoordinate2D ומגדירים את קו הרוחב וקו האורך למרכז המפה. אפשר לגשת לקואורדינטות של מרכז המפה מתצוגת המפה באמצעות המאפיינים camera.target.latitude ו-camera.target.longitude.

CLLocationCoordinate2D mapCenter = CLLocationCoordinate2DMake(_mapView.camera.target.latitude, _mapView.camera.target.longitude);
  1. ליצור מופע של GMSMarker.

‫Maps SDK ל-iOS מספק את המחלקה GMSMarker. כל מופע של GMSMarker מייצג סמן בודד במפה, והוא נוצר על ידי קריאה ל-markerWithPosition: והעברת אובייקט CLLocationCoordinate2D כדי לציין ל-SDK איפה למקם את הסמן במפה.

GMSMarker *marker = [GMSMarker markerWithPosition:mapCenter];
  1. הגדרת סמל מותאם אישית לסמן.

סמן הנעץ האדום שמופיע כברירת מחדל במפות Google הוא מצוין, אבל גם התאמה אישית של המפה היא אפשרות טובה. למזלנו, השימוש בסמן מותאם אישית הוא קל מאוד באמצעות Maps SDK ל-iOS. פרויקט StarterApp כולל תמונה בשם custom_pin.png שאפשר להשתמש בה, אבל אפשר להשתמש בכל תמונה שרוצים.

כדי להגדיר את הסמן המותאם אישית, מגדירים את מאפיין icon של הסמן למופע של UIImage.

marker.icon = [UIImage imageNamed:@"custom_pin.png"];
  1. מעבדים את הסמן במפה.

הסמן נוצר, אבל הוא לא מופיע במפה. כדי לעשות זאת, מגדירים את המאפיין map של מופע GMSMarker למופע של GMSMapView.

marker.map = _mapView;

עכשיו טוענים מחדש את האפליקציה ורואים את המפה הראשונה עם סמן!

a4ea8724f8c5ba20.png

לסיכום, בקטע הזה יצרתם מופע של המחלקה GMSMarker והחלתם אותו על תצוגת המפה כדי להציג סמן במפה. האירוע המעודכן במחזור החיים של viewDidLoad ב-ViewController.m אמור להיראות כך:

- (void)viewDidLoad {
  [super viewDidLoad];

  CLLocationCoordinate2D mapCenter = CLLocationCoordinate2DMake(_mapView.camera.target.latitude, _mapView.camera.target.longitude);
  GMSMarker *marker = [GMSMarker markerWithPosition:mapCenter];
  marker.icon = [UIImage imageNamed:@"custom_pin.png"];
  marker.map = _mapView;
}

7. הפעלת קיבוץ סמנים

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

6e39736160c6bce4.png

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

4abb38cd97cab3f1.png

האלגוריתם של קיבוץ סמנים מחלק את האזור הגלוי במפה לרשת, ואז מקבץ סמלים שנמצאים באותה משבצת. למזלכם, אתם לא צריכים לדאוג לגבי אף אחד מהדברים האלה, כי צוות הפלטפורמה של מפות Google יצר ספריית כלי עזר שימושית בקוד פתוח שנקראת Google Maps SDK for iOS Utility Library. הספרייה הזו, בין היתר, מטפלת באשכולות של סמנים באופן אוטומטי. מידע נוסף על קיבוץ סמנים זמין במסמכי התיעוד של הפלטפורמה של מפות Google. אפשר גם לעיין בקוד של ספריית כלי השירות ל-iOS ב-GitHub.

  1. להוסיף עוד הרבה סמנים למפה.

כדי לראות את הקיבוץ של הסמנים בפעולה, צריך שיהיו הרבה סמנים במפה. כדי להקל על התהליך, בפרויקט המתחיל ב-LocationGenerator.m יש כלי נוח ליצירת סמנים.

כדי להוסיף למפה כמה סמנים שרוצים, פשוט קוראים ל-generateMarkersNear:count: במחזור החיים של viewDidLoad בבקר התצוגה, מתחת לקוד מהשלב הקודם. השיטה יוצרת את מספר הסמנים שצוין ב-count במיקומים אקראיים סביב הקואורדינטות שצוינו באובייקט CLLocationCoordinate2D. במקרה כזה, אפשר פשוט להעביר את המשתנה mapCenter שיצרתם קודם. הסמנים מוחזרים ב-NSArray.

NSArray<GMSMarker *> *markerArray = [LocationGenerator generateMarkersNear:mapCenter count:100];
  1. מייבאים את ספריית כלי העזר של Google Maps SDK ל-iOS.

כדי להוסיף את ספריית כלי השירות של מפות Google ל-iOS כתלות לפרויקט, מוסיפים את השורה הבאה לרשימת התלויות בחלק העליון של ViewController.m:

@import GoogleMapsUtils;
  1. מגדירים את התוסף MarkerClusterer.

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

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

id<GMUClusterAlgorithm> algorithm = [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] init];

id<GMUClusterIconGenerator> clusterIconGenerator = [[GMUDefaultClusterIconGenerator alloc] init];

id<GMUClusterRenderer> renderer = [[GMUDefaultClusterRenderer alloc] initWithMapView:_mapView clusterIconGenerator:clusterIconGenerator];
  1. ליצור מופע של GMUClusterManager.

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

@implementation ViewController {
  GMSMapView *_mapView;
  GMUClusterManager *_clusterManager;
}

לאחר מכן, יוצרים את המופע של GMUClusterManager באירוע מחזור החיים viewDidLoad:

_clusterManager = [[GMUClusterManager alloc] initWithMap:_mapView algorithm:algorithm renderer:renderer];
  1. מוסיפים את הסמנים ומריצים את הכלי לאשכול סמנים.

עכשיו, אחרי שהגדרתם את מופע marker clusterer, כל מה שצריך לעשות הוא להעביר למנהל האשכולים את מערך הסמנים שרוצים לאגד לאשכולות על ידי קריאה ל-addItems:, ואז להפעיל את ה-clusterer על ידי קריאה ל-cluster.

[_clusterManager addItems:markerArray];
[_clusterManager cluster];

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

c49383b07752bfc4.png

לסיכום, בשלב הזה הגדרתם מופע של כלי לאיחוד סמנים מתוך ספריית כלי השירות של Google Maps SDK ל-iOS, ואז השתמשתם בו כדי לאחד 100 סמנים במפה. האירוע במחזור החיים viewDidLoad ב-ViewController.m אמור להיראות עכשיו כך:

- (void)viewDidLoad {
  [super viewDidLoad];

  CLLocationCoordinate2D mapCenter = CLLocationCoordinate2DMake(_mapView.camera.target.latitude,
                                                                _mapView.camera.target.longitude);
  GMSMarker *marker = [GMSMarker markerWithPosition:mapCenter];
  marker.icon = [UIImage imageNamed:@"custom_pin.png"];
  marker.map = _mapView;
  NSArray<GMSMarker *> *markerArray = [LocationGenerator generateMarkersNear:mapCenter count:100];

  id<GMUClusterAlgorithm> algorithm = [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] init];
  id<GMUClusterIconGenerator> clusterIconGenerator = [[GMUDefaultClusterIconGenerator alloc] init];
  id<GMUClusterRenderer> renderer = [[GMUDefaultClusterRenderer alloc] initWithMapView:_mapView clusterIconGenerator:clusterIconGenerator];
  _clusterManager = [[GMUClusterManager alloc] initWithMap:_mapView algorithm:algorithm renderer:renderer];

  [_clusterManager addItems:markerArray];
  [_clusterManager cluster];
}

8. הוספת אינטראקציה של משתמש

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

ערכת Maps SDK ל-iOS מספקת מערכת אירועים מקיפה שמיושמת באמצעות נציג תצוגת המפה, שכוללת מטפלי אירועים שמאפשרים להריץ קוד כשמתרחשות אינטראקציות שונות של משתמשים. לדוגמה, נציג mapview כולל שיטות שמאפשרות להפעיל ביצוע קוד לאינטראקציות כמו קליק של המשתמש על המפה ועל סמנים, הזזה של תצוגת המפה, הגדלה והקטנה של התצוגה ועוד.

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

  1. מטמיעים את ה-event listener של הקשה על סמן.

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

כדי להטמיע את מאזין האירועים, מתחילים ביצירת stub שלו בתחתית של ViewController.m לפני ההצהרה end.

אפשר לראות שהשיטה מחזירה NO. הפעולה הזו אומרת ל-iOS SDK להמשיך להריץ את הפונקציונליות של GMSMarker שמוגדרת כברירת מחדל, כמו הצגת חלון מידע אם הוא מוגדר, אחרי הרצת קוד ה-handler של האירוע.

- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {

  return NO;
}
  1. מטפלים באירוע ההקשה ומפעילים אנימציה של המצלמה כדי למרכז מחדש את המפה כשמקישים על סמן או על קבוצת סמנים.

כשקוראים ל-mapView:didTapMarker, הוא מעביר את המופע של GMSMarker שהמשתמש הקיש עליו, וכך אפשר לטפל בו בקוד. אפשר להשתמש במופע הזה כדי למרכז מחדש את המפה על ידי קריאה ל-animateToLocation: בתצוגת המפה מתוך handler האירועים, והעברת המיקום של מופע הסמן, שזמין במאפיין position.

[_mapView animateToLocation:marker.position];
  1. הגדלת התצוגה של קבוצת סמנים כשמקישים עליה.

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

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

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

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

if ([marker.userData conformsToProtocol:@protocol(GMUCluster)]) {
    [_mapView animateToZoom:_mapView.camera.zoom +1];
    return YES;
}

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

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

השיטה mapView:didTapMarker אמורה להיראות כך:

- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {
  [_mapView animateToLocation:marker.position];

  if ([marker.userData conformsToProtocol:@protocol(GMUCluster)]) {
    [_mapView animateToZoom:_mapView.camera.zoom +1];
    return YES;
  }

  return NO;
}

9. ציור על המפה

עד עכשיו יצרתם מפה של סידני שמוצגים בה סמנים ב-100 נקודות אקראיות, וטיפלתם באינטראקציה של המשתמשים. בשלב האחרון של ה-codelab הזה, תשתמשו בתכונות הציור של Maps SDK for iOS כדי להוסיף תכונה שימושית נוספת לחוויית השימוש במפה.

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

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

  1. מוסיפים משתנה מופע _circ להטמעה של ViewController.

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

כדי לעשות זאת, מעדכנים את ההטמעה של ViewController באופן הבא:

@implementation ViewController {
  GMSMapView *_mapView;
  GMUClusterManager *_clusterManager;
  GMSCircle *_circ;
}
  1. לשרטט את העיגול כשמקישים על סמן.

בחלק התחתון של השיטה mapView:didTapMarker, מוסיפים את הקוד הבא כדי ליצור מופע של המחלקה GMSCircle של iOS SDK כדי לשרטט מעגל חדש ברדיוס של 800 מטרים על ידי קריאה ל-circleWithPosition:radius: והעברת המיקום של הסמן שהקשתם עליו, בדיוק כמו שעשיתם למעלה כשמרכזתם מחדש את המפה.

_circ = [GMSCircle circleWithPosition:marker.position radius:800];
  1. מעצבים את המעגל.

כברירת מחדל, GMSCircle מצייר עיגול עם קו שחור ומילוי שקוף. השיטה הזו תעבוד כדי להציג את הרדיוס, אבל היא לא נראית טוב במיוחד וקצת קשה לראות אותה. לאחר מכן, נותנים לעיגול צבע מילוי כדי לשפר את הסגנון על ידי הקצאת UIColor למאפיין fillColor של העיגול. הקוד הבא יוסיף מילוי אפור עם שקיפות של 50%:

_circ.fillColor = [UIColor colorWithRed: 0.67 green: 0.67 blue: 0.67 alpha: 0.5];
  1. הצגת המעגל במפה.

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

_circ.map = _mapView;
  1. מסירים את כל המעגלים שנוצרו קודם.

כמו שצוין קודם, חוויית המשתמש לא תהיה טובה אם פשוט נוסיף עוד עיגולים למפה. כדי להסיר את העיגול שנוצר על ידי אירוע הקשה קודם, מגדירים את המאפיין map של _circ ל-nil בחלק העליון של mapView:didTapMarker.

_circ.map = nil;

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

342520482a888519.png

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

השיטה mapView:didTapMarker אמורה להיראות כך:

- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {
  _circ.map = nil;
  [_mapView animateToLocation:marker.position];

  if ([marker.userData conformsToProtocol:@protocol(GMUCluster)]) {
    [_mapView animateToZoom:_mapView.camera.zoom +1];
    return YES;
  }

  _circ = [GMSCircle circleWithPosition:marker.position radius:800];
  _circ.fillColor = [UIColor colorWithRed: 0.67 green: 0.67 blue: 0.67 alpha: 0.5];
  _circ.map = _mapView;
  return NO;
}

10. מזל טוב

הצלחתם לפתח את אפליקציית ה-iOS הראשונה שלכם באמצעות הפלטפורמה של מפות Google, כולל טעינה של Maps SDK for iOS, טעינה של מפה, עבודה עם סמנים, שליטה במפה ושרטוט עליה והוספה של אינטראקציה עם המשתמש.

כדי לראות את הקוד המלא, אפשר לעיין בפרויקט המוגמר בספרייה /solution.

מה השלב הבא?

ב-codelab הזה כיסינו רק את הבסיס של מה שאפשר לעשות עם Maps SDK ל-iOS. אחר כך, נסו להוסיף למפה חלק מהתכונות האלה:

  • אפשר לשנות את סוג המפה כדי להציג מפות לוויין, מפות היברידיות ומפות טופוגרפיות.
  • התאמה אישית של אינטראקציות אחרות של משתמשים, כמו התקרבות והתרחקות ופקדים של המפה.
  • מוסיפים חלונות מידע כדי להציג מידע כשלוחצים על סמנים.
  • כדאי לעיין ב-Places SDK ל-iOS כדי להוסיף לאפליקציה תכונות ונתונים עשירים של מקומות מהפלטפורמה של מפות Google.

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