1. शुरू करने से पहले
इस कोडलैब में, आपको अपने ऐप्लिकेशन में Maps SDK for Android को इंटिग्रेट करने का तरीका बताया गया है. साथ ही, इसकी मुख्य सुविधाओं का इस्तेमाल करने का तरीका भी बताया गया है. इसके लिए, एक ऐसा ऐप्लिकेशन बनाया गया है जो अलग-अलग तरह के मार्कर का इस्तेमाल करके, अमेरिका के कोलोराडो में मौजूद पहाड़ों का मैप दिखाता है. इसके अलावा, आपको मैप पर अन्य शेप बनाने का तरीका भी बताया जाएगा.
कोड लैब पूरा करने के बाद, यह इस तरह दिखेगा:
ज़रूरी शर्तें
- Kotlin, Jetpack Compose, और Android डेवलपमेंट के बारे में बुनियादी जानकारी
आपको क्या करना होगा
- Android ऐप्लिकेशन में
GoogleMap
जोड़ने के लिए, Android के लिए Maps SDK टूल के लिए Maps Compose लाइब्रेरी को चालू करें और उसका इस्तेमाल करें - मार्कर जोड़ना और उन्हें पसंद के मुताबिक बनाना
- मैप पर पॉलीगॉन बनाना
- प्रोग्राम के हिसाब से कैमरे के व्यू पॉइंट को कंट्रोल करना
आपको किन चीज़ों की ज़रूरत होगी
- Android के लिए Maps SDK
- बिलिंग की सुविधा वाला Google खाता
- Android Studio का सबसे नया स्टेबल वर्शन
- Android 5.0 या इसके बाद के वर्शन पर चलने वाला Android डिवाइस या Android एम्युलेटर. (इंस्टॉल करने के तरीके के लिए, Android एम्युलेटर पर ऐप्लिकेशन चलाना लेख पढ़ें.)
- इंटरनेट कनेक्शन
2. सेट अप करें
इसके बाद, आपको Android के लिए Maps SDK चालू करना होगा.
Google Maps Platform सेट अप करना
अगर आपके पास Google Cloud Platform खाता और बिलिंग की सुविधा वाला प्रोजेक्ट नहीं है, तो बिलिंग की सुविधा वाला खाता और प्रोजेक्ट बनाएं. ऐसा करने का तरीका जानने के लिए, कृपया Google Maps Platform का इस्तेमाल शुरू करना देखें.
- Cloud Console में, प्रोजेक्ट वाले ड्रॉप-डाउन मेन्यू पर क्लिक करें. इसके बाद, उस प्रोजेक्ट को चुनें जिसे इस कोडलैब के लिए इस्तेमाल करना है.
- इस कोडलैब के लिए ज़रूरी Google Maps Platform API और एसडीके को Google Cloud Marketplace में जाकर चालू करें. ऐसा करने के लिए, इस वीडियो या दस्तावेज़ में बताया गया तरीका अपनाएं.
- Cloud Console के क्रेडेंशियल पेज पर जाकर, एक एपीआई पासकोड जनरेट करें. ऐसा करने के लिए, इस वीडियो या दस्तावेज़ में बताया गया तरीका अपनाएं. Google Maps Platform का इस्तेमाल करने के लिए, एपीआई पासकोड ज़रूरी है.
3. तुरंत शुरू करना
इस कोडलैब को जल्द से जल्द शुरू करने के लिए, यहां कुछ शुरुआती कोड दिए गए हैं. आपके पास सीधे समाधान पर जाने का विकल्प है. हालांकि, अगर आपको इसे खुद बनाने के लिए सभी चरणों का पालन करना है, तो पढ़ना जारी रखें.
- अगर आपने
git
इंस्टॉल किया है, तो रिपॉज़िटरी को क्लोन करें.
git clone https://github.com/googlemaps-samples/codelab-maps-platform-101-compose.git
इसके अलावा, सोर्स कोड को डाउनलोड करने के लिए, इस बटन पर क्लिक करें.
- कोड मिलने के बाद, Android Studio में
starter
डायरेक्ट्री में मौजूद प्रोजेक्ट खोलें.
4. प्रोजेक्ट में एपीआई पासकोड जोड़ना
इस सेक्शन में, एपीआई पासकोड को सेव करने का तरीका बताया गया है, ताकि आपका ऐप्लिकेशन इसे सुरक्षित तरीके से रेफ़र कर सके. आपको अपने वर्शन कंट्रोल सिस्टम में एपीआई पासकोड की जांच नहीं करनी चाहिए. इसलिए, हम इसे secrets.properties
फ़ाइल में सेव करने का सुझाव देते हैं. यह फ़ाइल, आपके प्रोजेक्ट की रूट डायरेक्ट्री की लोकल कॉपी में रखी जाएगी. secrets.properties
फ़ाइल के बारे में ज़्यादा जानने के लिए, Gradle प्रॉपर्टी फ़ाइलें देखें.
इस काम को आसान बनाने के लिए, हमारा सुझाव है कि Android के लिए सीक्रेट ग्रेडल प्लग इन का इस्तेमाल करें.
अपने Google Maps प्रोजेक्ट में, Android के लिए Secrets Gradle Plugin इंस्टॉल करने के लिए:
- Android Studio में, अपनी टॉप-लेवल
build.gradle.kts
फ़ाइल खोलें. इसके बाद,buildscript
में मौजूदdependencies
एलिमेंट में यह कोड जोड़ें.buildscript { dependencies { classpath("com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1") } }
- मॉड्यूल-लेवल की
build.gradle.kts
फ़ाइल खोलें औरplugins
एलिमेंट में यह कोड जोड़ें.plugins { // ... id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") }
- अपने मॉड्यूल-लेवल की
build.gradle.kts
फ़ाइल में, पक्का करें किtargetSdk
औरcompileSdk
की वैल्यू कम से कम 34 पर सेट हो. - फ़ाइल सेव करें और अपने प्रोजेक्ट को Gradle के साथ सिंक करें.
- अपनी टॉप-लेवल डायरेक्ट्री में
secrets.properties
फ़ाइल खोलें. इसके बाद, यह कोड जोड़ें.YOUR_API_KEY
को अपने एपीआई पासकोड से बदलें. अपनी कुंजी को इस फ़ाइल में सेव करें, क्योंकिsecrets.properties
को वर्शन कंट्रोल सिस्टम में शामिल नहीं किया जाता है.MAPS_API_KEY=YOUR_API_KEY
- फ़ाइल सेव करें.
- अपनी टॉप-लेवल डायरेक्ट्री में
local.defaults.properties
फ़ाइल बनाएं. यह फ़ाइल,secrets.properties
फ़ाइल वाले फ़ोल्डर में ही होनी चाहिए. इसके बाद, यह कोड जोड़ें. इस फ़ाइल का मकसद, एपीआई पासकोड के लिए बैकअप की जगह उपलब्ध कराना है. ऐसा तब किया जाता है, जबMAPS_API_KEY=DEFAULT_API_KEY
secrets.properties
फ़ाइल नहीं मिलती है, ताकि बिल्ड न रुकें. ऐसा तब होता है, जब आपने वर्शन कंट्रोल सिस्टम से ऐप्लिकेशन को क्लोन किया हो और आपने एपीआई पासकोड देने के लिए, अब तक स्थानीय तौर परsecrets.properties
फ़ाइल नहीं बनाई हो. - फ़ाइल सेव करें.
- अपनी
AndroidManifest.xml
फ़ाइल में,com.google.android.geo.API_KEY
पर जाएं औरandroid:value
एट्रिब्यूट को अपडेट करें. अगर<meta-data>
टैग मौजूद नहीं है, तो इसे<application>
टैग के चाइल्ड के तौर पर बनाएं.<meta-data android:name="com.google.android.geo.API_KEY" android:value="${MAPS_API_KEY}" />
- Android Studio में, अपने मॉड्यूल-लेवल की
build.gradle.kts
फ़ाइल खोलें औरsecrets
प्रॉपर्टी में बदलाव करें. अगरsecrets
प्रॉपर्टी मौजूद नहीं है, तो उसे जोड़ें.प्लगिन की प्रॉपर्टी में बदलाव करके,propertiesFileName
कोsecrets.properties
पर सेट करें,defaultPropertiesFileName
कोlocal.defaults.properties
पर सेट करें, और अन्य प्रॉपर्टी सेट करें.secrets { // Optionally specify a different file name containing your secrets. // The plugin defaults to "local.properties" propertiesFileName = "secrets.properties" // A properties file containing default secret values. This file can be // checked in version control. defaultPropertiesFileName = "local.defaults.properties" }
5. Google Maps जोड़ना
इस सेक्शन में, आपको एक Google मैप जोड़ना होगा, ताकि ऐप्लिकेशन लॉन्च करने पर वह लोड हो जाए.
Maps Compose डिपेंडेंसी जोड़ना
अब आपके ऐप्लिकेशन में एपीआई पासकोड को ऐक्सेस किया जा सकता है. इसलिए, अगला चरण यह है कि अपने ऐप्लिकेशन की build.gradle.kts
फ़ाइल में, Maps SDK for Android की डिपेंडेंसी जोड़ें. Jetpack Compose का इस्तेमाल करके ऐप्लिकेशन बनाने के लिए, Maps Compose लाइब्रेरी का इस्तेमाल करें. यह लाइब्रेरी, Maps SDK for Android के एलिमेंट को कंपोज़ेबल फ़ंक्शन और डेटा टाइप के तौर पर उपलब्ध कराती है.
build.gradle.kts
ऐप्लिकेशन लेवल की build.gradle.kts
फ़ाइल में, कंपोज़ नहीं की गई Maps SDK for Android डिपेंडेंसी बदलें:
dependencies {
// ...
// Google Maps SDK -- these are here for the data model. Remove these dependencies and replace
// with the compose versions.
implementation("com.google.android.gms:play-services-maps:18.2.0")
// KTX for the Maps SDK for Android library
implementation("com.google.maps.android:maps-ktx:5.0.0")
// KTX for the Maps SDK for Android Utility Library
implementation("com.google.maps.android:maps-utils-ktx:5.0.0")
}
इन्हें कंपोज़ेबल फ़ंक्शन के साथ इस्तेमाल किया जा सकता है:
dependencies {
// ...
// Google Maps Compose library
val mapsComposeVersion = "4.4.1"
implementation("com.google.maps.android:maps-compose:$mapsComposeVersion")
// Google Maps Compose utility library
implementation("com.google.maps.android:maps-compose-utils:$mapsComposeVersion")
// Google Maps Compose widgets library
implementation("com.google.maps.android:maps-compose-widgets:$mapsComposeVersion")
}
Google मैप कंपोज़ेबल जोड़ना
MountainMap.kt
में, MapMountain
कंपोज़ेबल में नेस्ट किए गए Box
कंपोज़ेबल के अंदर GoogleMap
कंपोज़ेबल जोड़ें.
import com.google.maps.android.compose.GoogleMap
import com.google.maps.android.compose.GoogleMapComposable
// ...
@Composable
fun MountainMap(
paddingValues: PaddingValues,
viewState: MountainsScreenViewState.MountainList,
eventFlow: Flow<MountainsScreenEvent>,
selectedMarkerType: MarkerType,
) {
var isMapLoaded by remember { mutableStateOf(false) }
Box(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
) {
// Add GoogleMap here
GoogleMap(
modifier = Modifier.fillMaxSize(),
onMapLoaded = { isMapLoaded = true }
)
// ...
}
}
अब ऐप्लिकेशन बनाएं और उसे चलाएं. बधाई हो! आपको एक मैप दिखेगा. यह मैप, कुख्यात नल आइलैंड पर केंद्रित होगा. इसे अक्षांश शून्य और देशांतर शून्य के नाम से भी जाना जाता है. बाद में, आपको मैप को अपनी पसंद की जगह और ज़ूम लेवल पर सेट करने का तरीका बताया जाएगा. फ़िलहाल, अपनी पहली जीत का जश्न मनाएं!
6. क्लाउड पर मैप की स्टाइलिंग
क्लाउड पर मैप की स्टाइलिंग की सुविधाओं का इस्तेमाल करके, अपने मैप में मनमुताबिक स्टाइल जोड़े जा सकते हैं.
मैप आईडी बनाना
अगर आपने अब तक मैप आईडी नहीं बनाया है और उसे अपने मैप के स्टाइल से नहीं जोड़ा है, तो इसका तरीका जानने और अपनाने के लिए, मैप के आईडी गाइड देखें:
- मैप आईडी बनाना.
- मैप के किसी स्टाइल से एक मैप आईडी जोड़ना.
अपने ऐप्लिकेशन में मैप आईडी जोड़ना
आपने जो मैप आईडी बनाया है उसका इस्तेमाल करने के लिए, GoogleMap
कंपोज़ेबल को इंस्टैंटिएट करते समय, मैप आईडी का इस्तेमाल करके GoogleMapOptions
ऑब्जेक्ट बनाएं. इसके बाद, इसे कंस्ट्रक्टर में googleMapOptionsFactory
पैरामीटर को असाइन करें.
GoogleMap(
// ...
googleMapOptionsFactory = {
GoogleMapOptions().mapId("MyMapId")
}
)
यह प्रोसेस पूरी करने के बाद, ऐप्लिकेशन चलाएं और अपने चुने गए स्टाइल में मैप देखें!
7. मार्कर का डेटा लोड करना
इस ऐप्लिकेशन का मुख्य काम, लोकल स्टोरेज से पहाड़ों का कलेक्शन लोड करना और उन पहाड़ों को GoogleMap
में दिखाना है. इस चरण में, आपको माउंटेन डेटा लोड करने और उसे यूज़र इंटरफ़ेस (यूआई) पर दिखाने के लिए उपलब्ध कराए गए इंफ़्रास्ट्रक्चर के बारे में जानकारी मिलेगी.
पहाड़
Mountain
डेटा क्लास में, हर पर्वत के बारे में पूरा डेटा होता है.
data class Mountain(
val id: Int,
val name: String,
val location: LatLng,
val elevation: Meters,
)
ध्यान दें कि बाद में पहाड़ों को उनकी ऊंचाई के हिसाब से बांटा जाएगा. कम से कम 14,000 फ़ीट ऊंचे पहाड़ों को फ़ोर्टीनर कहा जाता है. स्टार्टर कोड में एक एक्सटेंशन फ़ंक्शन शामिल होता है. यह फ़ंक्शन आपके लिए इस जांच को पूरा करता है.
/**
* Extension function to determine whether a mountain is a "14er", i.e., has an elevation greater
* than 14,000 feet (~4267 meters).
*/
fun Mountain.is14er() = elevation >= 14_000.feet
MountainsScreenViewState
MountainsScreenViewState
क्लास में, व्यू को रेंडर करने के लिए ज़रूरी सारा डेटा होता है. यह Loading
या MountainList
स्थिति में हो सकता है. यह इस बात पर निर्भर करता है कि पहाड़ों की सूची लोड हो गई है या नहीं.
/**
* Sealed class representing the state of the mountain map view.
*/
sealed class MountainsScreenViewState {
data object Loading : MountainsScreenViewState()
data class MountainList(
// List of the mountains to display
val mountains: List<Mountain>,
// Bounding box that contains all of the mountains
val boundingBox: LatLngBounds,
// Switch indicating whether all the mountains or just the 14ers
val showingAllPeaks: Boolean = false,
) : MountainsScreenViewState()
}
ये क्लास उपलब्ध हैं: MountainsRepository
और MountainsViewModel
स्टार्टर प्रोजेक्ट में, आपको MountainsRepository
क्लास दी गई है. यह क्लास, पहाड़ों की उन जगहों की सूची को पढ़ती है जो GPS Exchange Format
या GPX फ़ाइल में सेव की गई हैं top_peaks.gpx
. mountainsRepository.loadMountains()
को कॉल करने पर, StateFlow<List<Mountain>>
मिलता है.
MountainsRepository
class MountainsRepository(@ApplicationContext val context: Context) {
private val _mountains = MutableStateFlow(emptyList<Mountain>())
val mountains: StateFlow<List<Mountain>> = _mountains
private var loaded = false
/**
* Loads the list of mountains from the list of mountains from the raw resource.
*/
suspend fun loadMountains(): StateFlow<List<Mountain>> {
if (!loaded) {
loaded = true
_mountains.value = withContext(Dispatchers.IO) {
context.resources.openRawResource(R.raw.top_peaks).use { inputStream ->
readMountains(inputStream)
}
}
}
return mountains
}
/**
* Reads the [Waypoint]s from the given [inputStream] and returns a list of [Mountain]s.
*/
private fun readMountains(inputStream: InputStream) =
readWaypoints(inputStream).mapIndexed { index, waypoint ->
waypoint.toMountain(index)
}.toList()
// ...
}
MountainsViewModel
MountainsViewModel
एक ViewModel
क्लास है. यह पहाड़ों के कलेक्शन को लोड करती है और mountainsScreenViewState
के ज़रिए, उस कलेक्शन के साथ-साथ यूज़र इंटरफ़ेस (यूआई) की स्थिति के अन्य हिस्सों को भी दिखाती है. mountainsScreenViewState
एक हॉट StateFlow
है. यूज़र इंटरफ़ेस (यूआई) इसे collectAsState
एक्सटेंशन फ़ंक्शन का इस्तेमाल करके, बदलने वाली स्थिति के तौर पर देख सकता है.
MountainsViewModel
, ऐप्लिकेशन की सभी स्थितियों को सेव करता है. ऐसा, साउंड आर्किटेक्चर के सिद्धांतों के मुताबिक किया जाता है. यूज़र इंटरफ़ेस, onEvent
तरीके का इस्तेमाल करके, उपयोगकर्ता के इंटरैक्शन को व्यू मॉडल में भेजता है.
@HiltViewModel
class MountainsViewModel
@Inject
constructor(
mountainsRepository: MountainsRepository
) : ViewModel() {
private val _eventChannel = Channel<MountainsScreenEvent>()
// Event channel to send events to the UI
internal fun getEventChannel() = _eventChannel.receiveAsFlow()
// Whether or not to show all of the high peaks
private var showAllMountains = MutableStateFlow(false)
val mountainsScreenViewState =
mountainsRepository.mountains.combine(showAllMountains) { allMountains, showAllMountains ->
if (allMountains.isEmpty()) {
MountainsScreenViewState.Loading
} else {
val filteredMountains =
if (showAllMountains) allMountains else allMountains.filter { it.is14er() }
val boundingBox = filteredMountains.map { it.location }.toLatLngBounds()
MountainsScreenViewState.MountainList(
mountains = filteredMountains,
boundingBox = boundingBox,
showingAllPeaks = showAllMountains,
)
}
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = MountainsScreenViewState.Loading
)
init {
// Load the full set of mountains
viewModelScope.launch {
mountainsRepository.loadMountains()
}
}
// Handle user events
fun onEvent(event: MountainsViewModelEvent) {
when (event) {
OnZoomAll -> onZoomAll()
OnToggleAllPeaks -> toggleAllPeaks()
}
}
private fun onZoomAll() {
sendScreenEvent(MountainsScreenEvent.OnZoomAll)
}
private fun toggleAllPeaks() {
showAllMountains.value = !showAllMountains.value
}
// Send events back to the UI via the event channel
private fun sendScreenEvent(event: MountainsScreenEvent) {
viewModelScope.launch { _eventChannel.send(event) }
}
}
अगर आपको इन क्लास को लागू करने के बारे में ज़्यादा जानना है, तो GitHub पर जाकर इन्हें ऐक्सेस किया जा सकता है. इसके अलावा, Android Studio में MountainsRepository
और MountainsViewModel
क्लास खोली जा सकती हैं.
ViewModel का इस्तेमाल करना
MainActivity
में व्यू मॉडल का इस्तेमाल, viewState
पाने के लिए किया जाता है. इस कोडलैब में, बाद में मार्कर रेंडर करने के लिए viewState
का इस्तेमाल किया जाएगा. ध्यान दें कि यह कोड, स्टार्टर प्रोजेक्ट में पहले से ही शामिल है. इसे यहां सिर्फ़ रेफ़रंस के लिए दिखाया गया है.
val viewModel: MountainsViewModel by viewModels()
val screenViewState = viewModel.mountainsScreenViewState.collectAsState()
val viewState = screenViewState.value
8. कैमरे को सही जगह पर रखें
GoogleMap
डिफ़ॉल्ट रूप से, अक्षांश शून्य और देशांतर शून्य पर होता है. आपको जिन मार्कर को रेंडर करना है वे अमेरिका के कोलोराडो राज्य में मौजूद हैं. व्यू मॉडल से मिले viewState
में, LatLngBounds मौजूद होता है. इसमें सभी मार्कर शामिल होते हैं.
MountainMap.kt
में, बाउंडिंग बॉक्स के सेंटर पर सेट किया गया CameraPositionState
बनाएं. GoogleMap
के cameraPositionState
पैरामीटर को, अभी-अभी बनाए गए cameraPositionState
वैरिएबल पर सेट करें.
fun MountainMap(
// ...
) {
// ...
val cameraPositionState = rememberCameraPositionState {
position = CameraPosition.fromLatLngZoom(viewState.boundingBox.center, 5f)
}
GoogleMap(
// ...
cameraPositionState = cameraPositionState,
)
}
अब कोड चलाएं और देखें कि मैप, कोलोराडो पर फ़ोकस कर रहा है.
मार्कर की सीमाओं पर ज़ूम करें
मैप को मार्कर पर फ़ोकस करने के लिए, MountainMap.kt
फ़ाइल के आखिर में zoomAll
फ़ंक्शन जोड़ें. ध्यान दें कि इस फ़ंक्शन के लिए CoroutineScope
की ज़रूरत होती है, क्योंकि कैमरे को नई जगह पर ले जाने की प्रोसेस एसिंक्रोनस होती है. इसे पूरा होने में समय लगता है.
fun zoomAll(
scope: CoroutineScope,
cameraPositionState: CameraPositionState,
boundingBox: LatLngBounds
) {
scope.launch {
cameraPositionState.animate(
update = CameraUpdateFactory.newLatLngBounds(boundingBox, 64),
durationMs = 1000
)
}
}
इसके बाद, मार्कर कलेक्शन के आस-पास की सीमाएं बदलने पर या जब उपयोगकर्ता TopApp बार में ज़ूम एक्सटेंट बटन पर क्लिक करता है, तब zoomAll
फ़ंक्शन को लागू करने के लिए कोड जोड़ें. ध्यान दें कि ज़ूम एक्सटेंट बटन को पहले से ही व्यू मॉडल को इवेंट भेजने के लिए कॉन्फ़िगर किया गया है. आपको सिर्फ़ व्यू मॉडल से उन इवेंट को इकट्ठा करना होगा और जवाब में zoomAll
फ़ंक्शन को कॉल करना होगा.
fun MountainMap(
// ...
) {
// ...
val scope = rememberCoroutineScope()
LaunchedEffect(key1 = viewState.boundingBox) {
zoomAll(scope, cameraPositionState, viewState.boundingBox)
}
LaunchedEffect(true) {
eventFlow.collect { event ->
when (event) {
MountainsScreenEvent.OnZoomAll -> {
zoomAll(scope, cameraPositionState, viewState.boundingBox)
}
}
}
}
}
अब ऐप्लिकेशन चलाने पर, मैप उस जगह पर फ़ोकस करेगा जहां मार्कर लगाए जाएंगे. मैप की जगह बदली जा सकती है और उसे ज़ूम किया जा सकता है. ज़ूम एक्सटेंट बटन पर क्लिक करने से, मैप मार्कर वाली जगह पर फिर से फ़ोकस करेगा. यह तो कमाल हो गया! हालांकि, मैप में कुछ न कुछ दिखना चाहिए. अगले चरण में आपको यही करना है!
9. बुनियादी मार्कर
इस चरण में, आपको मैप में मार्कर जोड़ने होते हैं. ये मार्कर, उन लोकप्रिय जगहों को दिखाते हैं जिन्हें आपको मैप पर हाइलाइट करना है. आपको स्टार्टर प्रोजेक्ट में दी गई पहाड़ों की सूची का इस्तेमाल करना होगा. साथ ही, इन जगहों को मैप पर मार्कर के तौर पर जोड़ना होगा.
GoogleMap
में कॉन्टेंट ब्लॉक जोड़कर शुरुआत करें. मार्कर कई तरह के होंगे. इसलिए, हर टाइप में ब्रांच करने के लिए when
स्टेटमेंट जोड़ें. इसके बाद, अगले चरणों में हर टाइप को लागू करें.
GoogleMap(
// ...
) {
when (selectedMarkerType) {
MarkerType.Basic -> {
BasicMarkersMapContent(
mountains = viewState.mountains,
)
}
MarkerType.Advanced -> {
AdvancedMarkersMapContent(
mountains = viewState.mountains,
)
}
MarkerType.Clustered -> {
ClusteringMarkersMapContent(
mountains = viewState.mountains,
)
}
}
}
मार्कर जोड़ना
@GoogleMapComposable
की मदद से BasicMarkersMapContent
को एनोटेट करें. ध्यान दें कि GoogleMap
कॉन्टेंट ब्लॉक में सिर्फ़ @GoogleMapComposable
फ़ंक्शन का इस्तेमाल किया जा सकता है. mountains
ऑब्जेक्ट में Mountain
ऑब्जेक्ट की सूची होती है. आपको उस सूची में मौजूद हर पर्वत के लिए एक मार्कर जोड़ना होगा. इसके लिए, Mountain
ऑब्जेक्ट से मिली जगह, नाम, और ऊंचाई की जानकारी का इस्तेमाल करें. इस जगह का इस्तेमाल, Marker
के स्टेट पैरामीटर को सेट करने के लिए किया जाता है. इससे मार्कर की पोज़िशन कंट्रोल होती है.
// ...
import com.google.android.gms.maps.model.Marker
import com.google.maps.android.compose.GoogleMapComposable
import com.google.maps.android.compose.Marker
import com.google.maps.android.compose.rememberMarkerState
@Composable
@GoogleMapComposable
fun BasicMarkersMapContent(
mountains: List<Mountain>,
onMountainClick: (Marker) -> Boolean = { false }
) {
mountains.forEach { mountain ->
Marker(
state = rememberMarkerState(position = mountain.location),
title = mountain.name,
snippet = mountain.elevation.toElevationString(),
tag = mountain,
onClick = { marker ->
onMountainClick(marker)
false
},
zIndex = if (mountain.is14er()) 5f else 2f
)
}
}
अब ऐप्लिकेशन चलाएं. आपको अभी-अभी जोड़े गए मार्कर दिखेंगे!
मार्कर को पसंद के मुताबिक बनाना
आपने जो मार्कर जोड़े हैं उन्हें पसंद के मुताबिक बनाने के लिए, कई विकल्प उपलब्ध हैं. इससे मार्कर को अलग से दिखाने और लोगों को काम की जानकारी देने में मदद मिलती है. इस टास्क में, हर मार्कर की इमेज को पसंद के मुताबिक बनाकर, उनमें से कुछ को एक्सप्लोर किया जाएगा.
स्टार्टर प्रोजेक्ट में, vectorToBitmap
नाम का एक हेल्पर फ़ंक्शन शामिल होता है. इसका इस्तेमाल, @DrawableResource
से BitmapDescriptor
बनाने के लिए किया जाता है.
स्टार्टर कोड में एक माउंटेन आइकॉन, baseline_filter_hdr_24.xml
शामिल है. इसका इस्तेमाल करके, मार्कर को पसंद के मुताबिक बनाया जा सकता है.
vectorToBitmap
फ़ंक्शन, वेक्टर ड्रॉएबल को BitmapDescriptor
में बदलता है, ताकि इसे Maps Library के साथ इस्तेमाल किया जा सके. आइकॉन के रंग, BitmapParameters
इंस्टेंस का इस्तेमाल करके सेट किए जाते हैं.
data class BitmapParameters(
@DrawableRes val id: Int,
@ColorInt val iconColor: Int,
@ColorInt val backgroundColor: Int? = null,
val backgroundAlpha: Int = 168,
val padding: Int = 16,
)
fun vectorToBitmap(context: Context, parameters: BitmapParameters): BitmapDescriptor {
// ...
}
vectorToBitmap
फ़ंक्शन का इस्तेमाल करके, दो कस्टम BitmapDescriptor
बनाएं. एक 4,267 मीटर से ज़्यादा ऊंचे पहाड़ों के लिए और दूसरा सामान्य पहाड़ों के लिए. इसके बाद, आइकॉन सेट करने के लिए Marker
कंपोज़ेबल के icon
पैरामीटर का इस्तेमाल करें. साथ ही, आइकॉन के हिसाब से ऐंकर की जगह बदलने के लिए, anchor
पैरामीटर सेट करें. सर्कुलर आइकॉन के लिए, सेंटर का इस्तेमाल करना बेहतर होता है.
@Composable
@GoogleMapComposable
fun BasicMarkersMapContent(
// ...
) {
// Create mountainIcon and fourteenerIcon
val mountainIcon = vectorToBitmap(
LocalContext.current,
BitmapParameters(
id = R.drawable.baseline_filter_hdr_24,
iconColor = MaterialTheme.colorScheme.secondary.toArgb(),
backgroundColor = MaterialTheme.colorScheme.secondaryContainer.toArgb(),
)
)
val fourteenerIcon = vectorToBitmap(
LocalContext.current,
BitmapParameters(
id = R.drawable.baseline_filter_hdr_24,
iconColor = MaterialTheme.colorScheme.onPrimary.toArgb(),
backgroundColor = MaterialTheme.colorScheme.primary.toArgb(),
)
)
mountains.forEach { mountain ->
val icon = if (mountain.is14er()) fourteenerIcon else mountainIcon
Marker(
// ...
anchor = Offset(0.5f, 0.5f),
icon = icon,
)
}
}
ऐप्लिकेशन चलाएं और अपनी पसंद के मुताबिक बनाए गए मार्कर देखें. पहाड़ों का पूरा सेट देखने के लिए, Show all
स्विच को टॉगल करें. पहाड़ों पर अलग-अलग मार्कर होंगे. यह इस बात पर निर्भर करेगा कि पहाड़ की ऊंचाई 14,000 फ़ीट से ज़्यादा है या नहीं.
10. ऐडवांस मार्कर
AdvancedMarker
, बुनियादी Markers
में अतिरिक्त सुविधाएं जोड़ते हैं. इस चरण में, टकराव की स्थिति में पिन के व्यवहार को सेट किया जाएगा और पिन की स्टाइल को कॉन्फ़िगर किया जाएगा.
@GoogleMapComposable
को AdvancedMarkersMapContent
फ़ंक्शन में जोड़ें. हर mountains
के लिए, एक AdvancedMarker
जोड़ें.
@Composable
@GoogleMapComposable
fun AdvancedMarkersMapContent(
mountains: List<Mountain>,
onMountainClick: (Marker) -> Boolean = { false },
) {
mountains.forEach { mountain ->
AdvancedMarker(
state = rememberMarkerState(position = mountain.location),
title = mountain.name,
snippet = mountain.elevation.toElevationString(),
collisionBehavior = AdvancedMarkerOptions.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL,
onClick = { marker ->
onMountainClick(marker)
false
}
)
}
}
collisionBehavior
पैरामीटर पर ध्यान दें. इस पैरामीटर को REQUIRED_AND_HIDES_OPTIONAL
पर सेट करने से, आपका मार्कर कम प्राथमिकता वाले किसी भी मार्कर की जगह ले लेगा. बेसिक मार्कर की तुलना में, अडवांस मार्कर को ज़ूम इन करके देखा जा सकता है. बेसिक मार्कर में, आपके मार्कर और बेस मैप में एक ही जगह पर रखे गए मार्कर, दोनों शामिल होंगे. ऐडवांस मार्कर की वजह से, कम प्राथमिकता वाला मार्कर छिप जाएगा.
ऐडवांस मार्कर देखने के लिए, ऐप्लिकेशन चलाएं. पक्का करें कि आपने सबसे नीचे मौजूद नेविगेशन बार में, Advanced markers
टैब चुना हो.
पसंद के मुताबिक बनाया गया AdvancedMarkers
आइकॉन में प्राइमरी और सेकंडरी कलर स्कीम का इस्तेमाल किया गया है, ताकि 4,267 मीटर से ज़्यादा ऊंचे पहाड़ों और अन्य पहाड़ों के बीच अंतर किया जा सके. vectorToBitmap
फ़ंक्शन का इस्तेमाल करके, दो BitmapDescriptor
बनाएं. एक 14,000 फ़ीट से ज़्यादा ऊंचाई वाले पहाड़ों के लिए और दूसरा अन्य पहाड़ों के लिए. इन आइकॉन का इस्तेमाल करके, हर टाइप के लिए कस्टम pinConfig
बनाएं. आखिर में, is14er()
फ़ंक्शन के आधार पर, पिन को उससे जुड़े AdvancedMarker
पर लागू करें.
@Composable
@GoogleMapComposable
fun AdvancedMarkersMapContent(
mountains: List<Mountain>,
onMountainClick: (Marker) -> Boolean = { false },
) {
val mountainIcon = vectorToBitmap(
LocalContext.current,
BitmapParameters(
id = R.drawable.baseline_filter_hdr_24,
iconColor = MaterialTheme.colorScheme.onSecondary.toArgb(),
)
)
val mountainPin = with(PinConfig.builder()) {
setGlyph(PinConfig.Glyph(mountainIcon))
setBackgroundColor(MaterialTheme.colorScheme.secondary.toArgb())
setBorderColor(MaterialTheme.colorScheme.onSecondary.toArgb())
build()
}
val fourteenerIcon = vectorToBitmap(
LocalContext.current,
BitmapParameters(
id = R.drawable.baseline_filter_hdr_24,
iconColor = MaterialTheme.colorScheme.onPrimary.toArgb(),
)
)
val fourteenerPin = with(PinConfig.builder()) {
setGlyph(PinConfig.Glyph(fourteenerIcon))
setBackgroundColor(MaterialTheme.colorScheme.primary.toArgb())
setBorderColor(MaterialTheme.colorScheme.onPrimary.toArgb())
build()
}
mountains.forEach { mountain ->
val pin = if (mountain.is14er()) fourteenerPin else mountainPin
AdvancedMarker(
state = rememberMarkerState(position = mountain.location),
title = mountain.name,
snippet = mountain.elevation.toElevationString(),
collisionBehavior = AdvancedMarkerOptions.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL,
pinConfig = pin,
onClick = { marker ->
onMountainClick(marker)
false
}
)
}
}
11. क्लस्टर किए गए मार्कर
इस चरण में, ज़ूम के आधार पर सामान को ग्रुप करने की सुविधा जोड़ने के लिए, Clustering
कंपोज़ेबल का इस्तेमाल किया जाएगा.
Clustering
कंपोज़ेबल के लिए, ClusterItem
का कलेक्शन ज़रूरी है. MountainClusterItem
, ClusterItem
इंटरफ़ेस लागू करता है. इस क्लास को ClusteringMarkersMapContent.kt
फ़ाइल में जोड़ें.
data class MountainClusterItem(
val mountain: Mountain,
val snippetString: String
) : ClusterItem {
override fun getPosition() = mountain.location
override fun getTitle() = mountain.name
override fun getSnippet() = snippetString
override fun getZIndex() = 0f
}
अब पहाड़ों की सूची से MountainClusterItem
बनाने के लिए कोड जोड़ें. ध्यान दें कि यह कोड, उपयोगकर्ता की भाषा के हिसाब से डिसप्ले यूनिट में बदलने के लिए UnitsConverter
का इस्तेमाल करता है. इसे CompositionLocal
का इस्तेमाल करके, MainActivity
में सेट अप किया जाता है
@OptIn(MapsComposeExperimentalApi::class)
@Composable
@GoogleMapComposable
fun ClusteringMarkersMapContent(
mountains: List<Mountain>,
// ...
) {
val unitsConverter = LocalUnitsConverter.current
val resources = LocalContext.current.resources
val mountainClusterItems by remember(mountains) {
mutableStateOf(
mountains.map { mountain ->
MountainClusterItem(
mountain = mountain,
snippetString = unitsConverter.toElevationString(resources, mountain.elevation)
)
}
)
}
Clustering(
items = mountainClusterItems,
)
}
इस कोड की मदद से, मार्कर को ज़ूम लेवल के हिसाब से क्लस्टर किया जाता है. बहुत बढ़िया!
क्लस्टर को पसंद के मुताबिक बनाना
अन्य मार्कर टाइप की तरह, क्लस्टर किए गए मार्कर को पसंद के मुताबिक बनाया जा सकता है. Clustering
कंपोज़ेबल का clusterItemContent
पैरामीटर, कस्टम कंपोज़ेबल ब्लॉक सेट करता है. इससे क्लस्टर न किए गए आइटम को रेंडर किया जा सकता है. मार्कर बनाने के लिए, @Composable
फ़ंक्शन लागू करें. SingleMountain
फ़ंक्शन, पसंद के मुताबिक बैकग्राउंड के रंग की स्कीम के साथ कंपोज़ेबल Material 3 Icon
को रेंडर करता है.
ClusteringMarkersMapContent.kt
में, मार्कर के लिए कलर स्कीम तय करने वाली डेटा क्लास बनाएं:
data class IconColor(val iconColor: Color, val backgroundColor: Color, val borderColor: Color)
इसके अलावा, ClusteringMarkersMapContent.kt
में किसी दी गई कलर स्कीम के लिए आइकॉन रेंडर करने वाला कंपोज़ेबल फ़ंक्शन बनाएं:
@Composable
private fun SingleMountain(
colors: IconColor,
) {
Icon(
painterResource(id = R.drawable.baseline_filter_hdr_24),
tint = colors.iconColor,
contentDescription = "",
modifier = Modifier
.size(32.dp)
.padding(1.dp)
.drawBehind {
drawCircle(color = colors.backgroundColor, style = Fill)
drawCircle(color = colors.borderColor, style = Stroke(width = 3f))
}
.padding(4.dp)
)
}
अब 4,267 मीटर से ज़्यादा ऊंचाई वाले पहाड़ों के लिए एक कलर स्कीम और अन्य पहाड़ों के लिए दूसरी कलर स्कीम बनाएं. clusterItemContent
ब्लॉक में, कलर स्कीम चुनें. यह इस बात पर निर्भर करती है कि दिया गया पहाड़ 4,000 मीटर से ज़्यादा ऊंचा है या नहीं.
fun ClusteringMarkersMapContent(
mountains: List<Mountain>,
// ...
) {
// ...
val backgroundAlpha = 0.6f
val fourteenerColors = IconColor(
iconColor = MaterialTheme.colorScheme.onPrimary,
backgroundColor = MaterialTheme.colorScheme.primary.copy(alpha = backgroundAlpha),
borderColor = MaterialTheme.colorScheme.primary
)
val otherColors = IconColor(
iconColor = MaterialTheme.colorScheme.secondary,
backgroundColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = backgroundAlpha),
borderColor = MaterialTheme.colorScheme.secondary
)
// ...
Clustering(
items = mountainClusterItems,
clusterItemContent = { mountainItem ->
val colors = if (mountainItem.mountain.is14er()) {
fourteenerColors
} else {
otherColors
}
SingleMountain(colors)
},
)
}
अब ऐप्लिकेशन चलाकर, अलग-अलग आइटम के पसंद के मुताबिक बनाए गए वर्शन देखें.
12. मैप पर जानकारी देने के लिए ड्रॉ करना
आपने मैप पर ड्रॉ करने का एक तरीका पहले ही देख लिया है. यह तरीका मार्कर जोड़ने का है. हालांकि, Maps SDK for Android में कई अन्य तरीके भी उपलब्ध हैं. इनकी मदद से, मैप पर काम की जानकारी दिखाई जा सकती है.
उदाहरण के लिए, अगर आपको मैप पर रास्ते और इलाके दिखाने हैं, तो इन्हें मैप पर दिखाने के लिए Polyline
और Polygon
का इस्तेमाल किया जा सकता है. इसके अलावा, अगर आपको किसी इमेज को ज़मीन की सतह पर फ़िट करना है, तो GroundOverlay
का इस्तेमाल करें.
इस टास्क में, आपको शेप बनाने का तरीका सिखाया जाएगा. खास तौर पर, कोलोराडो राज्य के चारों ओर आउटलाइन बनाने का तरीका. कोलोराडो की सीमा को 37°N और 41°N अक्षांश और 102°03'W और 109°03'W के बीच के तौर पर तय किया गया है. इससे आउटलाइन बनाना काफ़ी आसान हो जाता है.
स्टार्टर कोड में, डिग्री-मिनट-सेकंड नोटेशन को डेसिमल डिग्री में बदलने के लिए, DMS
क्लास शामिल है.
enum class Direction(val sign: Int) {
NORTH(1),
EAST(1),
SOUTH(-1),
WEST(-1)
}
/**
* Degrees, minutes, seconds utility class
*/
data class DMS(
val direction: Direction,
val degrees: Double,
val minutes: Double = 0.0,
val seconds: Double = 0.0,
)
fun DMS.toDecimalDegrees(): Double =
(degrees + (minutes / 60) + (seconds / 3600)) * direction.sign
डीएमएस क्लास की मदद से, कोलोराडो की सीमा को बनाया जा सकता है. इसके लिए, आपको चार कोनों की LatLng
जगह की जानकारी देनी होगी और उन्हें Polygon
के तौर पर रेंडर करना होगा. MountainMap.kt
में यह कोड जोड़ें
@Composable
@GoogleMapComposable
fun ColoradoPolygon() {
val north = 41.0
val south = 37.0
val east = DMS(WEST, 102.0, 3.0).toDecimalDegrees()
val west = DMS(WEST, 109.0, 3.0).toDecimalDegrees()
val locations = listOf(
LatLng(north, east),
LatLng(south, east),
LatLng(south, west),
LatLng(north, west),
)
Polygon(
points = locations,
strokeColor = MaterialTheme.colorScheme.tertiary,
strokeWidth = 3F,
fillColor = MaterialTheme.colorScheme.tertiaryContainer.copy(alpha = 0.3f),
)
}
अब GoogleMap
कॉन्टेंट ब्लॉक में ColoradoPolyon()
को कॉल करें.
@Composable
fun MountainMap(
// ...
) {
Box(
// ...
) {
GoogleMap(
// ...
) {
ColoradoPolygon()
}
}
}
अब ऐप्लिकेशन, कोलोराडो राज्य को हाइलाइट करता है. साथ ही, उसमें हल्का रंग भरता है.
13. KML लेयर और स्केल बार जोड़ना
इस आखिरी सेक्शन में, आपको अलग-अलग पर्वत श्रृंखलाओं के बारे में सामान्य जानकारी देनी होगी. साथ ही, मैप में स्केल बार जोड़ना होगा.
पर्वत शृंखलाओं की जानकारी
आपने पहले, कोलोराडो के चारों ओर एक आउटलाइन बनाई थी. यहां आपको मैप में ज़्यादा जटिल आकार जोड़ने हैं. स्टार्टर कोड में कीहोल मार्कअप लैंग्वेज या KML फ़ाइल शामिल होती है. इसमें अहम पर्वत श्रृंखलाओं की जानकारी होती है. Android Utility Library के लिए Maps SDK में, मैप में KML लेयर जोड़ने का फ़ंक्शन होता है. when
ब्लॉक के बाद, GoogleMap
कॉन्टेंट ब्लॉक में MapEffect
कॉल जोड़ें.MountainMap.kt
MapEffect
फ़ंक्शन को GoogleMap
ऑब्जेक्ट के साथ कॉल किया जाता है. यह उन एपीआई और लाइब्रेरी के बीच एक उपयोगी ब्रिज के तौर पर काम कर सकता है जिनमें कंपोज़िशन की सुविधा नहीं होती और जिनके लिए GoogleMap
ऑब्जेक्ट की ज़रूरत होती है.
fun MountainMap(
// ...
) {
var isMapLoaded by remember { mutableStateOf(false) }
val context = LocalContext.current
GoogleMap(
// ...
) {
// ...
when (selectedMarkerType) {
// ...
}
// This code belongs inside the GoogleMap content block, but outside of
// the 'when' statement
MapEffect(key1 = true) {map ->
val layer = KmlLayer(map, R.raw.mountain_ranges, context)
layer.addLayerToMap()
}
}
मैप स्केल जोड़ना
आखिरी टास्क के तौर पर, आपको मैप में स्केल जोड़ना होगा. ScaleBar
, स्केल कंपोज़ेबल को लागू करता है. इसे मैप में जोड़ा जा सकता है. ध्यान दें कि ScaleBar
नहीं है
@GoogleMapComposable
है. इसलिए, इसे GoogleMap
कॉन्टेंट में नहीं जोड़ा जा सकता. इसके बजाय, इसे मैप वाले Box
में जोड़ें.
Box(
// ...
) {
GoogleMap(
// ...
) {
// ...
}
ScaleBar(
modifier = Modifier
.padding(top = 5.dp, end = 15.dp)
.align(Alignment.TopEnd),
cameraPositionState = cameraPositionState
)
// ...
}
पूरी तरह से लागू किए गए कोडलैब को देखने के लिए, ऐप्लिकेशन चलाएं.
14. समाधान का कोड पाना
पूरे हो चुके कोडलैब का कोड डाउनलोड करने के लिए, इन कमांड का इस्तेमाल किया जा सकता है:
- अगर आपने
git
इंस्टॉल किया है, तो रिपॉज़िटरी को क्लोन करें.
$ git clone https://github.com/googlemaps-samples/codelab-maps-platform-101-compose.git
इसके अलावा, सोर्स कोड को डाउनलोड करने के लिए, इस बटन पर क्लिक करें.
- कोड मिलने के बाद, Android Studio में
solution
डायरेक्ट्री में मौजूद प्रोजेक्ट खोलें.
15. बधाई हो
बधाई हो! आपने काफ़ी कॉन्टेंट कवर कर लिया है. हमें उम्मीद है कि आपको Android के लिए Maps SDK में उपलब्ध मुख्य सुविधाओं के बारे में बेहतर जानकारी मिल गई होगी.
ज़्यादा जानें
- Android के लिए Maps SDK - अपने Android ऐप्लिकेशन के लिए, डाइनैमिक, इंटरैक्टिव, और पसंद के मुताबिक बनाए गए मैप, जगह की जानकारी, और भू-स्थानिक अनुभव बनाएं.
- Maps Compose Library - यह ओपन सोर्स कंपोज़ेबल फ़ंक्शन और डेटा टाइप का एक सेट है. इसका इस्तेमाल Jetpack Compose के साथ करके, अपना ऐप्लिकेशन बनाया जा सकता है.
- android-maps-compose - GitHub पर मौजूद सैंपल कोड, जिसमें इस कोडलैब में बताई गई सभी सुविधाओं के बारे में बताया गया है.
- Google Maps Platform की मदद से Android ऐप्लिकेशन बनाने के लिए, Kotlin के ज़्यादा कोडलैब