SwiftUI (Swift) की मदद से, अपने iOS ऐप्लिकेशन में मैप जोड़ना

1. शुरू करने से पहले

यह कोडलैब आपको SwiftUI के साथ iOS के लिए, मैप SDK टूल इस्तेमाल करने का तरीका बताता है.

स्क्रीनशॉट-iphone-12-black@2x.png

ज़रूरी बातें

  • स्विफ़्ट के बारे में बुनियादी जानकारी
  • SwiftUI के बारे में बुनियादी जानकारी

आप क्या कर पाएंगे!

  • SwiftUI का इस्तेमाल करके iOS ऐप्लिकेशन में Google Maps जोड़ने के लिए, iOS के लिए Maps SDK चालू करें और उसका इस्तेमाल करें.
  • मैप में मार्कर जोड़ें.
  • SwiftUI व्यू से ऑब्जेक्ट को GMSMapView ऑब्जेक्ट में पास करें और उलटा होने से भी ऐसा हो सकता है.

आपको इनकी ज़रूरत होगी

2. सेट अप करें

इस सुविधा को चालू करने के लिए, iOS के लिए Maps SDK टूल चालू करें.

Google Maps Platform सेट अप करना

अगर आपके पास पहले से Google Cloud Platform खाता नहीं है और बिलिंग की सुविधा चालू की गई है, तो कृपया बिलिंग खाता और प्रोजेक्ट बनाने के लिए, Google Maps Platform का इस्तेमाल शुरू करना गाइड देखें.

  1. Cloud Console में, प्रोजेक्ट ड्रॉप-डाउन मेन्यू पर क्लिक करें और वह प्रोजेक्ट चुनें जिसे आप इस कोडलैब के लिए इस्तेमाल करना चाहते हैं.

  1. Google Cloud Marketplace में, इस कोडलैब के लिए ज़रूरी Google Maps Platform API और SDK टूल चालू करें. ऐसा करने के लिए, इस वीडियो या इस दस्तावेज़ में दिया गया तरीका अपनाएं.
  2. Cloud Console के क्रेडेंशियल पेज में एपीआई कुंजी जनरेट करें. आप इस वीडियो या इस दस्तावेज़ में दिया गया तरीका अपना सकते हैं. Google Maps Platform पर सभी अनुरोधों के लिए एपीआई कुंजी ज़रूरी है.

3. स्टार्टर कोड डाउनलोड करें

इसे शुरू करने में आपकी मदद करने के लिए, यहां कुछ # कोड दिया गया है, ताकि इस कोडलैब के साथ आपको मदद मिल सके. आप जब चाहें, इस कार्यक्रम में हिस्सा ले सकते हैं. हालांकि, अगर आप इस समस्या को खुद हल करने के सभी तरीके जानना चाहते हैं, तो पढ़ते रहें.

  1. अगर आपने git इंस्टॉल किया हुआ है, तो रिपॉज़िटरी क्लोन करें.
git clone https://github.com/googlecodelabs/maps-ios-swiftui.git

इसके अलावा, आप सोर्स कोड डाउनलोड करने के लिए इस बटन पर क्लिक कर सकते हैं.

  1. कोड मिलने के बाद, cd टर्मिनल में starter/GoogleMapsSwiftUI डायरेक्ट्री में.
  2. iOS के लिए मैप SDK डाउनलोड करने के लिए carthage update --platform iOS चलाएं
  3. आखिर में, GoogleMapsSwiftUI.xcodeproj फ़ाइल को Xcode में खोलें

4. कोड की खास जानकारी

डाउनलोड किए गए स्टार्टर प्रोजेक्ट में, ये क्लास दी गई हैं और आपके लिए लागू की गई हैं:

  • AppDelegate - ऐप्लिकेशन UIApplicationDelegate का. iOS के लिए Maps SDK टूल यहां से काम करना शुरू करेगा.
  • City - एक ऐसी इमारत जो किसी शहर के बारे में बताती है (इसमें शहर का नाम और कोऑर्डिनेट शामिल है).
  • MapViewController - Google Map वाला कोई सामान्य UIKit UIViewController (GMSMapView)
  • SceneDelegate - ऐप्लिकेशन और #31 का UIWindowSceneDelegate जिसमें से ContentView इंस्टैंशिएट किया गया है.

इसके अलावा, नीचे दी गई क्लास का कुछ हिस्सा लागू होगा और यह कोडलैब (कोड बनाना सीखना) खत्म होने तक पूरा हो जाएगा:

  • ContentView - टॉप-लेवल का SwiftUI व्यू जिसमें आपका ऐप्लिकेशन शामिल है.
  • MapViewControllerBridge - एक क्लास, जो UIKit व्यू को SwiftUI व्यू पर जोड़ती है. खास तौर पर, यह वह क्लास है जो MapViewController को SwiftUI में ऐक्सेस करने लायक बनाती है.

5. SwiftUI बनाम UIKit का उपयोग करना

SwiftUI को iOS ऐप्लिकेशन बनाने के लिए, यूज़र इंटरफ़ेस (यूआई) फ़्रेमवर्क के तौर पर iOS 13 में यूज़र इंटरफ़ेस (यूआई) फ़्रेमवर्क के तौर पर पेश किया गया था. अपने पिछले UIKit की तुलना में, SwiftUI कई फ़ायदे देती है. उदाहरण के लिए:

  • स्थिति में बदलाव होने पर व्यू अपने-आप अपडेट हो जाते हैं. स्थिति नाम के ऑब्जेक्ट का इस्तेमाल करने पर, उनमें शामिल किसी भी मान में बदलाव होने से यूज़र इंटरफ़ेस (यूआई) अपने-आप अपडेट हो जाएगा.
  • लाइव झलक देखकर, आप तेज़ी से डेवलपमेंट कर सकते हैं. लाइव झलक देखने से, एम्युलेटर पर कोड बनाने और डिप्लॉय करने की ज़रूरत नहीं पड़ती. साथ ही, Xcode पर आसानी से SwiftUI व्यू की झलक देखी जा सकती है.
  • स्रोत का सच्चाई स्विफ़्ट में है. SwiftUI में सभी व्यू का स्विफ़्ट में एलान किया जाता है, इसलिए अब इंटरफ़ेस बिल्डर का इस्तेमाल करना ज़रूरी नहीं है.
  • UIKit के साथ इंटरोऑपरेट करता है. यूज़र इंटरफ़ेस (यूआई) के साथ इंटरऑपरेबिलिटी, यह पक्का करता है कि मौजूदा ऐप्लिकेशन अपने मौजूदा व्यू के साथ SwiftUI का इस्तेमाल बढ़ा सकें. इसके अलावा, लाइब्रेरी में अब भी SwiftUI काम नहीं करती, जैसे कि iOS के Maps SDK टूल का इस्तेमाल अब भी SwiftUI में किया जा सकता है.

कुछ कमियां भी हैं:

  • SwiftUI सिर्फ़ iOS 13 या उसके बाद वाले वर्शन पर उपलब्ध है.
  • Xcode की झलकों में व्यू हैरारकी (व्यू और व्यू ग्रुप के लेआउट का क्रम) की जांच नहीं की जा सकती.

SwiftUI स्टेट और डेटा फ़्लो

SwiftUI एलान वाले तरीके का इस्तेमाल करके, यूज़र इंटरफ़ेस (यूआई) बनाने का एक शानदार तरीका देता है. आप SwiftUI को बताते हैं कि वह आपके व्यू के साथ-साथ सभी अलग-अलग स्थितियों में कैसा दिखना चाहिए. बाकी का काम सिस्टम कर लेगा. जब भी कोई इवेंट या उपयोगकर्ता कार्रवाई की वजह से स्थिति में कोई बदलाव होता है, तो स्विफ़्टयूआई व्यू को अपडेट करता है. आम तौर पर, इस डिज़ाइन को एकतरफ़ा डेटा फ़्लो कहा जाता है. इस कोडलैब की खास बातें, इस कोडलैब के दायरे में नहीं आती हैं. हालांकि, हमारा सुझाव है कि आप राज्य और डेटा फ़्लो के, Apple&#39s के दस्तावेज़ों में इसके काम करने के तरीके के बारे में पढ़ें.

UIViewRepresentable या UIViewControllerRepresentable का इस्तेमाल करके, UIKit और SwiftUI को ब्रिज करना

iOS के लिए Maps SDK टूल, UIKit पर सबसे ऊपर बनाया गया है. अब तक यह SwiftUI के साथ काम नहीं करता है. इसलिए, SwiftUI में इसका इस्तेमाल करने के लिए यह UIViewRepresentable या UIViewControllerRepresentable का होना ज़रूरी है. इन प्रोटोकॉल की मदद से, SwikitUI को यूज़र इंटरफ़ेस (यूआई) के हिसाब से बनाए गए UIView और UIViewController को शामिल किया जा सकता है. आप SwiftUI व्यू में Google मैप जोड़ने के लिए किसी भी प्रोटोकॉल का इस्तेमाल कर सकते हैं. अगले चरण में, हम मैप वाले UIViewController को शामिल करने के लिए UIViewControllerRepresentable का इस्तेमाल करेंगे.

6. एक मैप जोड़ें

इस सेक्शन में, आप Google Maps को SwiftUI व्यू में जोड़ेंगे.

add-a-map-स्क्रीनशॉट@2x.png

अपनी एपीआई कुंजी जोड़ें

आपने पहले जो एपीआई कुंजी बनाई थी उसे iOS के Maps SDK टूल को देना होगा, ताकि आपके खाते को ऐप्लिकेशन में दिखाए जाने वाले मैप से जोड़ा जा सके.

अपनी एपीआई कुंजी देने के लिए, AppDelegate.swift फ़ाइल खोलें और application(_, didFinishLaunchingWithOptions) तरीके पर जाएं. फ़िलहाल, SDK टूल GMSServices.provideAPIKey() के ज़रिए शुरू किया गया है. स्ट्रिंग के साथ &YOUR_API_KEY&kot;. उस स्ट्रिंग को अपनी एपीआई कुंजी से बदलें. इस चरण को पूरा करने के बाद, ऐप्लिकेशन लॉन्च होने पर iOS के लिए Maps SDK टूल शुरू हो जाएगा.

MapViewControllerBridge का इस्तेमाल करके, Google Maps जोड़ना

अब आपकी एपीआई कुंजी, SDK टूल के साथ उपलब्ध कराई जा रही है. इसके बाद, ऐप्लिकेशन पर मैप दिखाना होगा.

स्टार्टर कोड में दिया गया व्यू कंट्रोलर, MapViewController के व्यू में फ़िलहाल GMSMapView है. हालांकि, यह व्यू कंट्रोलर यूज़र इंटरफ़ेस (यूआई) में बनाया गया था. इसलिए, आपको इस क्लास को SwiftUI पर ब्रिज करना होगा, ताकि इसका इस्तेमाल ContentView में किया जा सके. इसके लिए:

  1. फ़ाइल को Xcode में MapViewControllerBridge खोलें.

यह क्लास, UIViewControllerRepresentation के मुताबिक है, जो यूज़र इंटरफ़ेस (यूआई) को यूज़र इंटरफ़ेस (यूआई) पर रैप करने का अनुरोध करता है. इससे UIViewController का इस्तेमाल SwiftUI व्यू के तौर पर किया जा सकता है. दूसरे शब्दों में, इस प्रोटोकॉल के मुताबिक होने पर आप एक UIKit व्यू को SwiftUI व्यू पर ब्रिज कर सकते हैं. इस प्रोटोकॉल के पालन के लिए दो तरीकों से लागू करना ज़रूरी है:

  • makeUIViewController(context) - UIViewController को बनाने के लिए, SwiftUI इस तरीके का इस्तेमाल करता है. यहां आप UIViewController को इंस्टैंशिएट करेंगे और उसकी शुरुआती स्थिति पास करेंगे.
  • updateUIViewController(_, context) - स्थिति बदलने पर, यह तरीका SwiftUI ने कॉल किया है. यहां पर आप स्थिति में बदलाव के जवाब में, पहले से मौजूद UIViewController में बदलाव कर सकते हैं.
  1. MapViewController बनाएं

makeUIViewController(context) फ़ंक्शन के अंदर, एक नया MapViewController इंस्टैंशिएट करें और उसे नतीजे के तौर पर दें. ऐसा करने के बाद, MapViewControllerBridge अब ऐसा दिखेगा:

MapViewControllerBridge

import GoogleMaps
import SwiftUI

struct MapViewControllerBridge: UIViewControllerRepresentable {

  func makeUIViewController(context: Context) -> MapViewController {
    return MapViewController()
  }

  func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
  }
}

ContentView में MapViewControllerBridge का इस्तेमाल करना

अब जब MapViewControllerBridge, MapViewController का एक इंस्टेंस बना रहा है, तो अगला चरण, मैप के डिसप्ले के लिए ContentView में इस तरीके का इस्तेमाल करना है.

  1. फ़ाइल को Xcode में ContentView खोलें.

ContentView को SceneDelegate में इंस्टैंशिएट किया जाता है और इसमें टॉप-लेवल ऐप्लिकेशन व्यू शामिल होता है. इस फ़ाइल में मैप जोड़ा जाएगा.

  1. body प्रॉपर्टी में MapViewControllerBridge बनाएं.

इस फ़ाइल की body प्रॉपर्टी में, आपको पहले ही एक ZStack दिया जा चुका है और उसे लागू किया जा चुका है. ZStack में फ़िलहाल, शहरों की एक इंटरैक्टिव और ड्रैग की जा सकने वाली सूची है. आप इनका इस्तेमाल बाद के चरण में करेंगे. अभी के लिए, ZStack में MapViewControllerBridge को ZStack के पहले चाइल्ड व्यू के तौर पर बनाएं, ताकि ऐप्लिकेशन को शहर के व्यू की सूची के पीछे ऐप्लिकेशन में दिखाया जा सके. ऐसा करने पर, ContentView में body प्रॉपर्टी का कॉन्टेंट ऐसा दिखना चाहिए:

कॉन्टेंट व्यू

var body: some View {

  let scrollViewHeight: CGFloat = 80

  GeometryReader { geometry in
    ZStack(alignment: .top) {
      // Map
      MapViewControllerBridge()

      // Cities List
      CitiesList(markers: $markers) { (marker) in
        guard self.selectedMarker != marker else { return }
        self.selectedMarker = marker
        self.zoomInCenter = false
        self.expandList = false
      }  handleAction: {
        self.expandList.toggle()
      } // ...
    }
  }
}
  1. अब आगे बढ़ें और ऐप्लिकेशन चलाएं. अब आपको अपने डिवाइस की स्क्रीन पर मैप लोड दिखेगा. साथ ही, स्क्रीन पर सबसे नीचे शहरों की खींचकर ली जा सकने वाली सूची भी दिखेगी.

7. मैप में मार्कर जोड़ें

पिछले चरण में, आपने इंटरैक्शन करने वाली एक सूची के साथ मैप जोड़ा था. इस सूची में शहरों की सूची दिखाई गई है. इस सेक्शन में, आप उस सूची के हर शहर के लिए मार्कर जोड़ेंगे.

map-with-marks@2x.png

राज्य के रूप में मार्कर

ContentView फ़िलहाल, markers नाम की प्रॉपर्टी का एलान करता है. यह प्रॉपर्टी, GMSMarker स्टैटिक प्रॉपर्टी में बताए गए हर शहर के लिए, GMSMarker की सूची है. ध्यान दें कि इस प्रॉपर्टी को SwiftUI प्रॉपर्टी रैपर स्टेटस के साथ दिखाया गया है, ताकि यह बताया जा सके कि इसे SwiftUI मैनेज कर सकता है. इसलिए, अगर इस प्रॉपर्टी में कोई बदलाव मिलता है, जैसे कि मार्कर जोड़ना या हटाना, तो इस स्थिति का इस्तेमाल करने वाले व्यू अपडेट कर दिए जाएंगे.

कॉन्टेंट व्यू

  static let cities = [
    City(name: "San Francisco", coordinate: CLLocationCoordinate2D(latitude: 37.7576, longitude: -122.4194)),
    City(name: "Seattle", coordinate: CLLocationCoordinate2D(latitude: 47.6131742, longitude: -122.4824903)),
    City(name: "Singapore", coordinate: CLLocationCoordinate2D(latitude: 1.3440852, longitude: 103.6836164)),
    City(name: "Sydney", coordinate: CLLocationCoordinate2D(latitude: -33.8473552, longitude: 150.6511076)),
    City(name: "Tokyo", coordinate: CLLocationCoordinate2D(latitude: 35.6684411, longitude: 139.6004407))
  ]

  /// State for markers displayed on the map for each city in `cities`
  @State var markers: [GMSMarker] = cities.map {
    let marker = GMSMarker(position: $0.coordinate)
    marker.title = $0.name
    return marker
  }

ध्यान दें कि ContentView markers प्रॉपर्टी का इस्तेमाल करके, CitiesList क्लास में शहरों की सूची भेजी जा सकती है.

शहरों की सूची

struct CitiesList: View {

  @Binding var markers: [GMSMarker]

  var body: some View {
    GeometryReader { geometry in
      VStack(spacing: 0) {
        // ...
        // List of Cities
        List {
          ForEach(0..<self.markers.count) { id in
            let marker = self.markers[id]
            Button(action: {
              buttonAction(marker)
            }) {
              Text(marker.title ?? "")
            }
          }
        }.frame(maxWidth: .infinity)
      }
    }
  }
}

बाइंडिंग के ज़रिए राज्य को MapViewControllerBridge में पास करें

markers प्रॉपर्टी से डेटा दिखाने वाले शहरों की सूची के अलावा, इस प्रॉपर्टी को MapViewControllerBridge स्ट्रक्चर में भेजें, ताकि मैप पर उन मार्कर को दिखाने के लिए इसका इस्तेमाल किया जा सके. ऐसा करने के लिए:

  1. MapViewControllerBridge के अंदर @Binding के साथ एनोटेट की गई नई markers प्रॉपर्टी का एलान करें

MapViewControllerBridge

struct MapViewControllerBridge: : UIViewControllerRepresentable {
  @Binding var markers: [GMSMarker]
  // ...
}
  1. markers प्रॉपर्टी का इस्तेमाल करने के लिए, MapViewControllerBridge में updateUIViewController(_, context) वाला तरीका अपडेट करें

जैसा कि पिछले चरण में बताया गया था, स्थिति बदलने पर SwiftUI को updateUIViewController(_, context) कॉल करेगा. इस तरीके से #39; मैप को अपडेट करना चाहते हैं, इसलिए markers में मार्कर दिखाएं. ऐसा करने के लिए, आपको हर मार्कर की map प्रॉपर्टी अपडेट करनी होगी. इस चरण को पूरा करने के बाद, MapViewControllerBridge ऐसा दिखेगा:

import GoogleMaps
import SwiftUI

struct MapViewControllerBridge: UIViewControllerRepresentable {

  @Binding var markers: [GMSMarker]

  func makeUIViewController(context: Context) -> MapViewController {
    return MapViewController()
  }

  func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
    // Update the map for each marker
    markers.forEach { $0.map = uiViewController.map }
  }
}
  1. ContentView से MapViewControllerBridge तक markers की प्रॉपर्टी पास करें

आपने MapViewControllerBridge में नई प्रॉपर्टी जोड़ी है, इसलिए अब यह ज़रूरी है कि MapViewControllerBridge के लिए शुरुआती पैरामीटर में, इस प्रॉपर्टी की वैल्यू को पास किया जाए. इसलिए, अगर आप ऐप्लिकेशन बनाने की कोशिश करते हैं, तो आपको दिखेगा कि वह कंपाइल नहीं होगा. इसे ठीक करने के लिए, ContentView में अपडेट करें जहां MapViewControllerBridge बनाया गया है और markers प्रॉपर्टी को इस तरह पास करें:

struct ContentView: View {
  // ...
  var body: some View {
    // ...
    GeometryReader { geometry in
      ZStack(alignment: .top) {
        // Map
        MapViewControllerBridge(markers: $markers)
        // ...
      }
    }
  }
}

ध्यान दें कि markers में MapViewControllerBridge को पास करने के लिए $ का इस्तेमाल MapViewControllerBridge के लिए किया गया था, क्योंकि यह बाउंड प्रॉपर्टी है. $ का इस्तेमाल, Swift प्रॉपर्टी के रैपर के साथ करने के लिए, रिज़र्व किया गया प्रीफ़िक्स है. किसी राज्य पर लागू किए जाने पर, यह बाइंडिंग दिखाएगा.

  1. आगे बढ़ें और मैप पर दिखाए गए मार्कर देखने के लिए ऐप्लिकेशन चलाएं.

8. चुने गए शहर में ऐनिमेशन बनाएं

पिछले चरण में आपने मैप पर मार्कर जोड़े थे. इनमें से एक को SwiftUI व्यू से दूसरे व्यू में स्टेट पास किया जा रहा था. इस चरण में, इंटरैक्शन करने वाली सूची में टैप किए जाने के बाद, आप किसी शहर/मार्कर को ऐनिमेट करेंगे. ऐनिमेशन करने के लिए, आपको बदलाव की स्थिति बनने पर मैप और #39; के कैमरे की स्थिति में बदलाव करना होगा. मैप के कॉन्सेप्ट के बारे में ज़्यादा जानने के लिए, कैमरा और व्यू देखें.

ऐनिमेट सिटी

चुने गए शहर के लिए मैप को ऐनिमेट करें

मैप को किसी चुने गए शहर में ऐनिमेट करने के लिए:

  1. MapViewControllerBridge में नई बाइंडिंग तय करें

ContentView के पास राज्य का नाम selectedMarker होता है, जो शून्य से शुरू होता है और सूची में किसी शहर को चुनने पर वह अपडेट हो जाता है. इसका इस्तेमाल ContentView में CitiesList व्यू buttonAction से किया जाता है.

कॉन्टेंट व्यू

CitiesList(markers: $markers) { (marker) in
  guard self.selectedMarker != marker else { return }
  self.selectedMarker = marker
  // ...
}

जब भी selectedMarker बदलता है, तो MapViewControllerBridge को इस स्थिति के बदलाव के बारे में पता होना चाहिए, ताकि यह चुने गए मार्कर के लिए मैप को ऐनिमेट कर सके. इसलिए, GMSMarker टाइप के MapViewControllerBridge में एक नई बाइंडिंग तय करें और प्रॉपर्टी selectedMarker को नाम दें.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  @Binding var selectedMarker: GMSMarker?
}
  1. जब भी selectedMarker बदले, मैप को ऐनिमेट करने के लिए MapViewControllerBridge अपडेट करें

नई बाइंडिंग का एलान किए जाने के बाद, आपको MapViewControllerBridge और #39;s updateUIViewController_, context) फ़ंक्शन को अपडेट करना होगा, ताकि मैप चुने गए मार्कर को ऐनिमेट कर सके. नीचे दिए गए कोड को कॉपी करके ऐसा करें:

struct MapViewControllerBridge: UIViewControllerRepresentable {
  @Binding var selectedMarker: GMSMarker?

  func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
    markers.forEach { $0.map = uiViewController.map }
    selectedMarker?.map = uiViewController.map
    animateToSelectedMarker(viewController: uiViewController)
  }

  private func animateToSelectedMarker(viewController: MapViewController) {
    guard let selectedMarker = selectedMarker else {
      return
    }

    let map = viewController.map
    if map.selectedMarker != selectedMarker {
      map.selectedMarker = selectedMarker
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        map.animate(toZoom: kGMSMinZoomLevel)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
          map.animate(with: GMSCameraUpdate.setTarget(selectedMarker.position))
          DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
            map.animate(toZoom: 12)
          })
        }
      }
    }
  }
}

animateToSelectedMarker(viewController) फ़ंक्शन, GMSMapView's animate(with) फ़ंक्शन का इस्तेमाल करके मैप ऐनिमेशन का क्रम तय करेगा.

  1. MapViewControllerBridge के लिए, ContentView's selectedMarker का पास

जब MapViewControllerBridge को नई बाइंडिंग के बारे में बता दिया जाए, तो आगे बढ़ें और selectedMarker को पास करने के लिए ContentView को अपडेट करें, जहां MapViewControllerBridge को इंस्टैंशिएट किया गया.

कॉन्टेंट व्यू

struct ContentView: View {
  // ...
  var body: some View {
    // ...
    GeometryReader { geometry in
      ZStack(alignment: .top) {
        // Map
        MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker)
        // ...
      }
    }
  }
}

सूची में नया शहर चुने जाने पर यह चरण पूरा करने से अब मैप ऐनिमेट हो जाएगा.

शहर पर ज़ोर देने के लिए SwiftUI व्यू ऐनिमेट करें

SwiftUI व्यू को ऐनिमेट करना बहुत आसान बनाता है, क्योंकि यह स्टेट ट्रांज़िशन के लिए परफ़ॉर्म करने वाले ऐनिमेशन को हैंडल करेगा. इसे दिखाने के लिए, आप मैप ऐनिमेशन पूरा होने के बाद, चुने गए शहर पर व्यू को फ़ोकस करके और ऐनिमेशन जोड़ पाएंगे. ऐसा करने के लिए, नीचे दिया गया तरीका अपनाएं:

  1. onAnimationEnded को MapViewControllerBridge में बंद करें

मैप में ऐनिमेशन का क्रम जो आपने पहले जोड़ा था उसके बाद SwiftUI ऐनिमेशन किया जाएगा. इसलिए, MapViewControllerBridge में onAnimationEnded नाम के बंद होने का एलान करें और animateToSelectedMarker(viewController) तरीके के तहत आखिरी मैप ऐनिमेशन के बाद 0.5 सेकंड की देरी के बाद उसे बंद करें.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
    var onAnimationEnded: () -> ()

    private func animateToSelectedMarker(viewController: MapViewController) {
    guard let selectedMarker = selectedMarker else {
      return
    }

    let map = viewController.map
    if map.selectedMarker != selectedMarker {
      map.selectedMarker = selectedMarker
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        map.animate(toZoom: kGMSMinZoomLevel)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
          map.animate(with: GMSCameraUpdate.setTarget(selectedMarker.position))
          DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
            map.animate(toZoom: 12)
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
              // Invoke onAnimationEnded() once the animation sequence completes
              onAnimationEnded()
            })
          })
        }
      }
    }
  }
}
  1. MapViewControllerBridge में onAnimationEnded लागू करें

onAnimationEnded को बंद करें, जहां ContentView में MapViewControllerBridge को इंस्टैंशिएट किया जाता है. नीचे दिया गया कोड कॉपी करके उसे चिपकाएं, जो zoomInCenter नाम की नई स्थिति को जोड़ता है और यह clipShape का इस्तेमाल करके व्यू को बदलता है और zoomInCenter के मान के आधार पर, क्लिप के आकार का व्यास बदलता है

कॉन्टेंट व्यू

struct ContentView: View {
  @State var zoomInCenter: Bool = false
  // ...
  var body: some View {
    // ...
    GeometryReader { geometry in
      ZStack(alignment: .top) {
        // Map
        let diameter = zoomInCenter ? geometry.size.width : (geometry.size.height * 2)
        MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker, onAnimationEnded: {
          self.zoomInCenter = true
        })
        .clipShape(
           Circle()
             .size(
               width: diameter,
               height: diameter
             )
             .offset(
               CGPoint(
                 x: (geometry.size.width - diameter) / 2,
                 y: (geometry.size.height - diameter) / 2
               )
             )
        )
        .animation(.easeIn)
        .background(Color(red: 254.0/255.0, green: 1, blue: 220.0/255.0))
      }
    }
  }
}
  1. ऐनिमेशन देखने के लिए, ऐप्लिकेशन का इस्तेमाल करें!

9. SwiftUI को इवेंट भेजना

इस कदम में, आप GMSMapView से जारी हुए इवेंट सुनेंगे और उस इवेंट को SwiftUI को भेजेंगे. खास तौर पर, आप 'मैप व्यू' में डेलिगेशन सेट करेंगे और कैमरे के मूव इवेंट सुनेंगे. ऐसा इसलिए होगा कि जब कोई शहर फ़ोकस में हो और मैप के कैमरे को हाथ के जेस्चर (हाव-भाव) से मूव किया जाए, तो मैप व्यू पर फ़ोकस नहीं हटेगा. इससे आप मैप को ज़्यादा देख पाएंगे.

SwiftUI कोऑर्डिनेटर का इस्तेमाल करना

यह GMSMapView इवेंट से बाहर निकलता है, जैसे कि कैमरे की स्थिति में बदलाव होना या किसी मार्कर पर टैप करना. इन इवेंट को सुनने का तरीका GMSMapViewDelegate प्रोटोकॉल के ज़रिए मिलता है. SwiftUI, कोऑर्डिनेटर के कॉन्सेप्ट के बारे में बताती है, जिसका इस्तेमाल खास तौर पर UIKit व्यू कंट्रोलर की डेलिगेट के तौर पर किया जाता है. इसलिए, SwiftUI दुनिया में, एक कोऑर्डिनेटर को GMSMapViewDelegate प्रोटोकॉल का पालन करने की ज़िम्मेदारी होनी चाहिए. ऐसा करने के लिए, यह तरीका अपनाएं:

  1. MapViewControllerBridge में MapViewCoordinator नाम का एक कोऑर्डिनेटर बनाएं

MapViewControllerBridge क्लास में नेस्ट की गई क्लास बनाएं और उसे MapViewCoordinator में कॉल करें. इस क्लास को GMSMapViewDelegate के हिसाब से होना चाहिए और इसे MapViewControllerBridge को प्रॉपर्टी के तौर पर बताना चाहिए.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
    var mapViewControllerBridge: MapViewControllerBridge

    init(_ mapViewControllerBridge: MapViewControllerBridge) {
      self.mapViewControllerBridge = mapViewControllerBridge
    }
  }
}
  1. MapViewControllerBridge में makeCoordinator() लागू करें

इसके बाद, MapViewControllerBridge में makeCoordinator() तरीका लागू करें और पिछले चरण में बनाए गए MapViewCoodinator का इंस्टेंस दिखाएं.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeCoordinator() -> MapViewCoordinator {
    return MapViewCoordinator(self)
  }
}
  1. MapViewCoordinator को मैप व्यू के तौर पर सेट करें'

पसंद के मुताबिक बनाए गए कोऑर्डिनेटर के साथ, अगला कदम कोऑर्डिनेटर को व्यू कंट्रोलर और #39 के मैप व्यू के लिए डेलिगेट के तौर पर सेट करना है. ऐसा करने के लिए, makeUIViewController(context) में व्यू कंट्रोलर को शुरू करने की सेटिंग अपडेट करें. पिछले चरण से बनाया गया कोऑर्डिनेट, कॉन्टेक्स्ट ऑब्जेक्ट से ऐक्सेस किया जा सकेगा.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeUIViewController(context: Context) -> MapViewController {
    let uiViewController = MapViewController()
    uiViewController.map.delegate = context.coordinator
    return uiViewController
  }
  1. MapViewControllerBridge के लिए बंद करें, ताकि कैमरे को इवेंट के लिए आगे बढ़ाया जा सके

लक्ष्य को कैमरे के व्यू से अपडेट करना है, इसलिए mapViewWillMove में MapViewControllerBridge बूलियन स्वीकार करने वाली नई बंद प्रॉपर्टी का एलान करें. साथ ही, MapViewCoordinator में डेलिगेट के तरीके mapView(_, willMove) में इस क्लोज़र को शुरू करें. gesture की वैल्यू बंद करें, ताकि SwiftUI व्यू सिर्फ़ कैमरे के जेस्चर (हाव-भाव) से जुड़ी गतिविधियों पर प्रतिक्रिया दे सके.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  var mapViewWillMove: (Bool) -> ()
  //...

  final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
    // ...
    func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
      self.mapViewControllerBridge.mapViewWillMove(gesture)
    }
  }
}
  1. mapWillMove के लिए कोई वैल्यू पास करने के लिए, ContentView को अपडेट करें

MapViewControllerBridge को बंद होने की नई तारीख के साथ, कारोबार को बंद करने की इस नई वैल्यू को पास करने के लिए ContentView को अपडेट करें. इसके बाद, अगर मूव इवेंट किसी जेस्चर (हाव-भाव) से मिलता-जुलता हो, तो zoomInCenter को false पर ले जाएं. जब मैप को हाथ के जेस्चर (हाव-भाव) से मूव किया जाता है, तो यह मैप को पूरे व्यू में फिर से असरदार तरीके से दिखाएगा.

कॉन्टेंट व्यू

struct ContentView: View {
  @State var zoomInCenter: Bool = false
  // ...
  var body: some View {
    // ...
    GeometryReader { geometry in
      ZStack(alignment: .top) {
        // Map
        let diameter = zoomInCenter ? geometry.size.width : (geometry.size.height * 2)
        MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker, onAnimationEnded: {
          self.zoomInCenter = true
        }, mapViewWillMove: { (isGesture) in
          guard isGesture else { return }
          self.zoomInCenter = false
        })
        // ...
      }
    }
  }
}
  1. आगे बढ़ें और नए बदलावों को देखने के लिए ऐप्लिकेशन चलाएं!

10. बधाई हो

इसमें शामिल होने के लिए बधाई! आपने बहुत सारी जानकारी दी है और उम्मीद है कि आपने जो लेसन सीखे हैं उनसे आप अब iOS के लिए Maps SDK टूल का इस्तेमाल करके, अपना SwiftUI ऐप्लिकेशन बना पाएंगे.

आपने क्या सीखा

  • SwiftUI और UIKit में अंतर
  • UIViewControllerRepresentable का इस्तेमाल करके, SwiftUI और यूज़र इंटरफ़ेस (यूआई) के बीच पुल बनाने का तरीका
  • राज्य और बाइंडिंग की मदद से, मैप व्यू में बदलाव करने का तरीका
  • मैप व्यू में किसी इवेंट को कोऑर्डिनेटर का इस्तेमाल करके, SwiftUI पर भेजने का तरीका

आगे क्या करना है?

  • iOS के लिए Maps SDK टूल - iOS के लिए Maps SDK टूल का आधिकारिक दस्तावेज़
  • iOS के लिए जगहें SDK टूल - अपने आस-पास मौजूद कारोबार और लोकप्रिय जगहें ढूंढें
  • maps-sdk-for-ios-samples - GitHub पर मौजूद सैंपल कोड, जो iOS के लिए, Maps SDK टूल की सभी सुविधाएं दिखाता है.
  • SwiftUI - SwiftUI पर Apple का आधिकारिक दस्तावेज़
  • नीचे दिए गए सवाल का जवाब देकर, हम वह कॉन्टेंट बनाने में मदद करें जो आपके लिए सबसे ज़्यादा काम का हो सकता है:

आप कौनसे अन्य कोडलैब देखना चाहते हैं?

मैप पर डेटा विज़ुअलाइज़ेशन मेरे मैप की शैली को पसंद के मुताबिक बनाने के बारे में ज़्यादा जानें मैप में 3D इंटरैक्शन के लिए बनाना

क्या वह कोडलैब ऊपर सूची में दिया गया है जो आप ऊपर नहीं देना चाहते हैं? नई समस्या के लिए, यहां अनुरोध करें.