यह पोस्ट जुलाई 2023 में Google डेवलपर्स ग्रुप लंदन के लिए Google I/O Extended में दिए गए एक भाषण पर आधारित है। इस भाषण की स्लाइड यहाँ उपलब्ध हैं
यह कल्पना करना कठिन है कि जेटपैक कम्पोज़ 1.0 जुलाई 2021 में जारी किया गया था। दो साल आगे बढ़ें और Google Play पर शीर्ष 1000 ऐप्स में से 24% ने कम्पोज़ को अपना लिया है, यह समझना आसान है कि क्यों।
सभी उत्साह के बीच, आधुनिक एंड्रॉइड डेवलपमेंट का एक पहलू जिस पर मुझे लगता है कि कम ध्यान दिया जाता है, वह है Google मैप्स। मुझे SDK का उपयोग किए हुए काफी समय हो गया है, इसलिए मुझे यह देखकर सुखद आश्चर्य हुआ कि Google मैप्स समय के साथ तालमेल बिठा रहा है और अपनी खुद की कंपोज लाइब्रेरी जारी कर रहा है।
मैपिंग क्षेत्र में काम करने वाली कंपनियों और इंजीनियरों के लिए यह एक अच्छी खबर होगी। मोबाइल मैपिंग एक $35.5B उद्योग है, जिसके 2028 तक 19.83% की चक्रवृद्धि वार्षिक वृद्धि दर (CAGR) पर $87.7B तक बढ़ने का अनुमान है। स्रोत
यह क्यों महत्वपूर्ण है? एक बड़े बाजार का मतलब है मोबाइल मैपिंग के अनुप्रयोगों से राजस्व प्राप्त करने के लिए कंपनियों के लिए अधिक अवसर। इनमें सामान्य उपयोग के मामले, भोजन, किराने की डिलीवरी और राइड हेलिंग सेवाएँ शामिल हैं। हालाँकि, यदि आप गहराई से खोजते हैं, तो ऐसे अनुप्रयोग हैं जो तुरंत स्पष्ट नहीं होते हैं।
नीचे कुछ उदाहरण दिए गए हैं जो मुझे संक्षिप्त खोज के बाद मिल सके:
मोबाइल मैप स्मार्ट सिटी के लिए बहुत बढ़िया हैं, जो शहर की धड़कन को प्रबंधित करने और डेटा को बेहतर तरीके से देखने में मदद करते हैं ताकि इसकी चुनौतियों को बेहतर ढंग से समझा जा सके और उन पर प्रतिक्रिया की जा सके। शहर के योजनाकारों, आपातकालीन प्रतिक्रिया संगठनों या रोज़मर्रा के निवासियों के लिए उपयोगी।
संसाधन प्रबंधन को भी मानचित्रण समाधानों से लाभ मिलता है। कृषि से लेकर मछली पकड़ने, खनन से लेकर वानिकी तक, मानचित्र इस क्षेत्र में काम करने वालों को टिकाऊ तरीके से सामग्री प्राप्त करने के लिए सही निर्णय लेने का दृष्टिकोण प्रदान करते हैं।
परिवहन में मैपिंग तकनीक का बहुत ज़्यादा इस्तेमाल होता है। सिर्फ़ Google Maps या Uber जैसे उपभोक्ता ऐप ही नहीं, बल्कि व्यवसाय-स्तर के काम जैसे कि यह समझना कि किसी व्यवसाय के वाहनों का बेड़ा कहाँ स्थित है। परिवहन एजेंसियाँ ट्रैफ़िक को प्रबंधित करने और ट्रैफ़िक को आसान बनाने के लिए उसे कहाँ निर्देशित करना है, इस बारे में निर्णय लेने में मदद करने के लिए भी मैप का इस्तेमाल करती हैं।
अंततः, जलवायु परिवर्तन और मौसम के अप्रत्याशित होते जाने के कारण, मानचित्र मौसम विज्ञान एजेंसियों, आपातकालीन प्रतिक्रिया इकाइयों और वन्यजीव संरक्षणवादियों को यह समझने में मदद करते हैं कि हमारा विश्व किस प्रकार बदल रहा है और हम इसे कम करने के लिए सकारात्मक कदम उठाने हेतु क्या कर सकते हैं।
स्रोत:मोर्डोर इंटेलिजेंस , जीएमइनसाइट्स , एलाइड मार्केट रिसर्च , ईएमआर रिसर्च , गूगल अर्थ आउटरीच , रिसर्च एंड मार्केट्स
दुनिया भर में डेटा की उपलब्धता बढ़ने के साथ, यह सीखने का अच्छा समय है कि उस डेटा को मानचित्र पर कैसे रखा जाए। आइए ऐसा करें और कोड पर वापस आएँ।
Google Maps for Compose निम्नलिखित निर्भरताओं पर निर्भर करता है:
dependencies { implementation "com.google.maps.android:maps-compose:2.11.4" implementation "com.google.android.gms:play-services-maps:18.1.0" // Optional Util Library implementation "com.google.maps.android:maps-compose-utils:2.11.4" implementation 'com.google.maps.android:maps-compose-widgets:2.11.4' // Optional Accompanist permissions to request permissions in compose implementation "com.google.accompanist:accompanist-permissions:0.31.5-beta" }
Google Maps for Compose को Google Maps SDK के ऊपर बनाया गया है, इसलिए आपको Compose लाइब्रेरी और Maps SDK को आयात करना होगा। आपको Google Maps SDK में ज़्यादातर ऑब्जेक्ट का इस्तेमाल करने की ज़रूरत नहीं होगी, क्योंकि compose लाइब्रेरी इनमें से ज़्यादातर को Composables में लपेट देती है।
यूटिलिटीज और विजेट लाइब्रेरी वैकल्पिक निर्भरता हैं। यूटिलिटीज लाइब्रेरी मैप्स पर मार्करों को क्लस्टर करने की क्षमता प्रदान करती है, जबकि विजेट अतिरिक्त UI घटक प्रदान करते हैं। आप इन्हें बाद में उपयोग में देखेंगे।
इस पोस्ट के लिए, मैंने स्थान अनुमतियों का अनुरोध करने का तरीका प्रदर्शित करने के लिए Accompanist से अनुरोध अनुमति लाइब्रेरी को शामिल किया है, जो मानचित्रों के साथ अक्सर उपयोग की जाने वाली अनुमति है। Accompanist Google के लिए एक प्रायोगिक लाइब्रेरी है जिसे आज़माया जा सकता है और उन सुविधाओं के लिए फ़ीडबैक एकत्र किया जा सकता है जो अभी तक Jetpack Compose का हिस्सा नहीं हैं।
अंत में, आपको Google डेवलपर कंसोल पर जाना होगा, Google मैप्स SDK API कुंजी के लिए साइन अप करना होगा और इसे अपने प्रोजेक्ट में जोड़ना होगा। Google मैप्स डेवलपर दस्तावेज़ों पर यह कैसे करना है, इस बारे में एक गाइड है।
सुरक्षा सुझाव: Google डेवलपर कंसोल में अपनी API कुंजी को लॉक करें ताकि यह केवल आपके एप्लिकेशन के साथ काम करे। इससे किसी भी अनधिकृत उपयोग से बचा जा सकता है।
मानचित्र दिखाना नीचे दिए अनुसार सरल है:
setContent { val hydePark = LatLng(51.508610, -0.163611) val cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(hydePark, 10f) } GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState) { Marker( state = MarkerState(position = hydePark), title = "Hyde Park", snippet = "Marker in Hyde Park" ) } }
किसी क्षेत्र की स्थिति के साथ एक LatLng
ऑब्जेक्ट बनाएँ, और कैमरे की प्रारंभिक स्थिति निर्धारित करने के लिए इसे rememberCameraPositionState
के साथ संयोजन में उपयोग करें। यह विधि आपके हाथों का उपयोग करके या प्रोग्रामेटिक रूप से चलते समय मानचित्र की स्थिति को याद रखती है । इस विधि के बिना Compose प्रत्येक स्थिति परिवर्तन पर मानचित्र को उसकी प्रारंभिक स्थिति पर वापस पुनर्गणना करेगा।
इसके बाद, एक GoogleMap
कंपोज बनाएं और अपनी पसंद का मॉडिफायर और कैमरा स्टेट पास करें। GoogleMap
अतिरिक्त कंपोजेबल्स पास करने के लिए एक स्लॉट API भी प्रदान करता है, ये कंपोजेबल्स वही हैं जो आप मानचित्र पर बनाना चाहते हैं।
एक Marker
कंपोज़ेबल जोड़ें, फिर मार्कर की स्थिति को शामिल करते हुए एक MarkerState
जोड़ें। अंत में, मार्कर का शीर्षक और विवरण जोड़ें।
इसे चलाने से हाइड पार्क के मार्कर के साथ पश्चिमी लंदन का सुंदर हवाई दृश्य दिखाई देता है।
आप MarkerInfoWindowContent
Composable का उपयोग करके मार्कर की विंडो को कस्टमाइज़ कर सकते हैं। इसमें स्लॉट-आधारित API भी है, जिसका अर्थ है कि आप विंडो में अपने कस्टम UI को रेंडर करने के लिए अपने कंपोज़ेबल्स को पास कर सकते हैं।
setContent { val hydePark = LatLng(51.508610, -0.163611) val cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(hydePark, 10f) } GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState) { MarkerInfoWindowContent( state = MarkerState(position = hydePark), title = "Hyde Park", snippet = "Marker in Hyde Park" ) { marker -> Column(horizontalAlignment = Alignment.CenterHorizontally) { Text( modifier = Modifier.padding(top = 6.dp), text = marker.title ?: "", fontWeight = FontWeight.Bold ) Text("Hyde Park is a Grade I-listed parked in Westminster") Image( modifier = Modifier .padding(top = 6.dp) .border( BorderStroke(3.dp, color = Color.Gray), shape = RectangleShape ), painter = painterResource(id = R.drawable.hyde_park), contentDescription = "A picture of hyde park" ) } } } }
इसे चलाने पर जब आप मार्कर पर टैप करते हैं तो उसके ऊपर कस्टम विंडो दिखाई देती है।
कई मार्कर दिखाना उतना ही आसान है जितना कि आपको जितने की ज़रूरत है उतने जोड़ना। आइए वेस्ट लंदन के कुछ अलग-अलग पार्कों के लिए मार्कर जोड़ें।
setContent { val hydePark = LatLng(51.508610, -0.163611) val regentsPark = LatLng(51.531143, -0.159893) val primroseHill = LatLng(51.539556, -0.16076088) val cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(hydePark, 10f) } GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState) { // Marker 1 Marker( state = MarkerState(position = hydePark), title = "Hyde Park", snippet = "Marker in Hyde Park" ) // Marker 2 Marker( state = MarkerState(position = regentsPark), title = "Regents Park", snippet = "Marker in Regents Park" ) // Marker 3 Marker( state = MarkerState(position = primroseHill), title = "Primrose Hill", snippet = "Marker in Primrose Hill" ) } }
कोड चलाएँ और आप देखेंगे कि आपके मार्कर मानचित्र पर दिखाई देने लगेंगे।
एक नक्शा कुछ ही समय में व्यस्त हो सकता है। यदि आप 300 मार्कर दिखाने की कोशिश कर रहे हैं, तो उपयोगकर्ता के लिए यह समझना मुश्किल होगा कि क्या हो रहा है। Google मैप्स और आपका डिवाइस भी आपको धन्यवाद नहीं देगा, क्योंकि इसे हर एक मार्कर को रेंडर करना होगा, जिससे प्रदर्शन और बैटरी लाइफ़ प्रभावित होगी।
इसका समाधान क्लस्टरिंग है, जो एक ऐसी तकनीक है जो मार्करों को एक दूसरे के करीब एक मार्कर में समूहीकृत करती है। यह क्लस्टरिंग ज़ूम-स्तर के आधार पर होती है। जैसे ही आप मानचित्र को ज़ूम आउट करते हैं मार्कर एक क्लस्टर में समूहीकृत हो जाते हैं, जैसे ही आप ज़ूम इन करते हैं क्लस्टर अलग-अलग मार्करों में विभाजित हो जाता है।
गूगल मैप्स फॉर कंपोज इसे Clustering
कंपोजेबल के माध्यम से बॉक्स से बाहर प्रदान करता है। क्लस्टरिंग के लिए जटिल सॉर्टिंग या फ़िल्टरिंग लिखने की कोई आवश्यकता नहीं है।
setContent { val hydePark = LatLng(51.508610, -0.163611) val regentsPark = LatLng(51.531143, -0.159893) val primroseHill = LatLng(51.539556, -0.16076088) val crystalPalacePark = LatLng(51.42153, -0.05749) val greenwichPark = LatLng(51.476688, 0.000130) val lloydPark = LatLng(51.364188, -0.080703) val cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(hydePark, 10f) } GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState) { val parkMarkers = remember { mutableStateListOf( ParkItem(hydepark, "Hyde Park", "Marker in hyde Park"), ParkItem(regentspark, "Regents Park", "Marker in Regents Park"), ParkItem(primroseHill, "Primrose Hill", "Marker in Primrose Hill"), ParkItem(crystalPalacePark, "Crystal Palace", "Marker in Crystal Palace"), ParkItem(greenwichPark, "Greenwich Park", "Marker in Greenwich Park"), ParkItem(lloydPark, "Lloyd park", "Marker in Lloyd Park"), ) } Clustering(items = parkMarkers, onClusterClick = { // Handle when the cluster is tapped }, onClusterItemClick = { marker -> // Handle when a marker in the cluster is tapped }) } } data class ParkItem( val itemPosition: LatLng, val itemTitle: String, val itemSnippet: String) : ClusterItem { override fun getPosition(): LatLng = itemPosition override fun getTitle(): String = itemTitle override fun getSnippet(): String = itemSnippet }
ParkItem
डेटा क्लास को जोड़े जाने पर ध्यान दें। हमें इसकी आवश्यकता है क्योंकि Clustering
कंपोज़ेबल में पास किए गए आइटम को ClusterItem
इंटरफ़ेस के अनुरूप होना चाहिए। इंटरफ़ेस क्लस्टर को प्रत्येक मार्कर के लिए स्थिति, शीर्षक और स्निपेट प्रदान करता है।
ज़ूम इन और ज़ूम आउट करें, और आप क्लस्टरिंग को क्रियान्वित होते देखेंगे।
मानचित्र और उपयोगकर्ता की स्थिति अक्सर एक साथ चलते हैं, इसलिए कुछ मानचित्रण ऐप्स के लिए उपयोगकर्ता के स्थान के लिए अनुमति मांगना उचित है।
यदि आप ऐसा करते हैं तो उपयोगकर्ता की अनुमति का सम्मान करें , स्थान अनुमति उपयोगकर्ता से प्राप्त की जाने वाली सबसे संवेदनशील अनुमतियों में से एक है।
सुनिश्चित करें कि आप उपयोगकर्ता को बताएं कि आपको इस अनुमति की आवश्यकता क्यों है और इसे देने के लाभों को सक्रिय रूप से दिखाएं। बोनस अंक यदि आपका ऐप बिना किसी अनुमति की आवश्यकता के आंशिक रूप से कार्य करता है।
गूगल उपयोगकर्ताओं के स्थान को संभालने के बारे में कुछ बेहतरीन गाइड प्रदान करता है, साथ ही पृष्ठभूमि में स्थान डेटा तक पहुंचने के लिए एक अलग गाइड भी प्रदान करता है।
तो आपने अपना उचित परिश्रम किया है और निर्णय लिया है कि आपको स्थान तक पहुँचने के लिए उपयोगकर्ता की अनुमति की आवश्यकता है। Accompanist में अनुमति लाइब्रेरी के साथ, आप इसे इस तरह करते हैं:
// Don't forget to add the permissions to AndroidManifest.xml val allLocationPermissionState = rememberMultiplePermissionsState( listOf(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION) ) // Check if we have location permissions if (!allLocationPermissionsState.allPermissionsGranted) { // Show a component to request permission from the user Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, modifier = Modifier .padding(horizontal = 36.dp) .clip(RoundedCornerShape(16.dp)) .background(Color.white) ) { Text( modifier = Modifier.padding(top = 6.dp), textAlign = TextAlign.Center, text = "This app functions 150% times better with percise location enabled" ) Button(modifier = Modifier.padding(top = 12.dp), onClick = { allLocationPermissionsState.launchMultiplePermissionsRequest() }) { Text(text = "Grant Permission") } } }
सहायक के माध्यम से, हम यह जाँच रहे हैं कि क्या ऐप के पास ACCESS_FINE_LOCATION
अनुमति या अंग्रेजी में GPS सटीकता का उच्च स्तर है। Android मेनिफ़ेस्ट में अनुरोधित अनुमतियों को शामिल करना महत्वपूर्ण है, क्योंकि आप अन्यथा अनुमतियों का अनुरोध नहीं कर पाएंगे।
एंड्रॉइड सिस्टम और गूगल प्ले स्टोर भी आपके ऐप के काम करने के तरीके को समझने और उपयोगकर्ताओं को सूचित करने के लिए मेनिफेस्ट का उपयोग करते हैं।
यदि अनुमति नहीं दी जाती है, तो एक छोटा सा संवाद दिखाया जाता है जिसमें अनुमति की आवश्यकता के बारे में बताया जाता है और सिस्टम के माध्यम से अनुमति अनुरोध शुरू करने के लिए एक बटन दिखाया जाता है।
जबकि अधिकांश मैप ऐप्स के लिए उपयोगकर्ता को टच के माध्यम से मैप को स्थानांतरित करने की आवश्यकता होती है, Google मैप्स फॉर कंपोज मैप को प्रोग्रामेटिक रूप से स्थानांतरित करने के लिए API प्रदान करता है। यह तब उपयोगी हो सकता है जब आप किसी ईवेंट के जवाब में किसी विशिष्ट क्षेत्र में नेविगेट करना चाहते हैं।
इस उदाहरण में, हम अपने मार्करों के संग्रह के माध्यम से ऐप को धीरे-धीरे नेविगेट करेंगे।
Box(contentAlignment = Alignment.Center) { GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState ) { Clustering(items = parkMarkers, onClusterClick = { // Handle when the click is tapped false }, onClusterItemClick = { marker -> // Handle when the marker is tapped }) LaunchedEffect(key1 = "Animation") { for (marker in parkMarkers) { cameraPositionState.animate( CameraUpdateFactory.newLatLngZoom( marker.itemPosition, // LatLng 16.0f), // Zoom level 2000 // Animation duration in millis ), delay(4000L) // Delay in millis } } } }
यहाँ मुख्य भाग LaunchedEffect
के अंदर का कोड है। प्रत्येक मार्कर के लिए, ऐप मार्कर पर नेविगेट करने के लिए cameraPositionState.animate()
कॉल सेट करता है। कैमरा यह जानकारी कैमरे के अपडेट के माध्यम से प्राप्त करता है, CameraUpdateFactory.newLatLngZoom()
का उपयोग करके बनाया जाता है।
यह विधि LatLng
, मानचित्र के ज़ूम स्तर को इंगित करने वाला एक फ्लोट तथा एनीमेशन की अवधि निर्धारित करने के लिए एक long लेती है।
अंत में, एनिमेशन के बीच अंतराल रखने के लिए हम delay()
प्रयोग करते हैं, जिससे प्रत्येक एनिमेशन के बीच 4 सेकंड का विराम आता है।
यह सिर्फ़ हवाई नक्शा नहीं है जिसकी मदद से Google Maps for Compose आपकी मदद करता है। आप ऐप्स को स्ट्रीट व्यू तक पहुंच भी दे सकते हैं, जो किसी स्थान का 360 डिग्री व्यू दिखाता है। आप StreetView
कंपोजेबल का उपयोग करके ऐसा कर सकते हैं:
var selectedMarker: ParkItem? by remember { mutableStateOf(null) } if (selectedMarker != null) { StreetView(Modifier.fillMaxSize(), streetViewPanoramaOptionsFactory = { StreetViewPanoramaOptions().position(selectedMarker!!.position) }) } else { Box(contentAlignment = Alignment.Center) { GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState ) { Clustering(items = parkMarkers, onClusterClick = { // Handle when the cluster is clicked false }, onClusterItemClick = { marker -> // Handle when a marker in the cluster is clicked selectedMarker = marker false }) } } }
इस उदाहरण में, जब भी कोई मार्कर टैप किया जाता है, तो हम selectedMarker
वैरिएबल सेट कर रहे हैं। यदि कोई मार्कर चुना जाता है, तो हम मार्कर की स्थिति में पासिंग करते हुए स्ट्रीट व्यू दिखाते हैं।
आप मानचित्र पर अपनी खुद की आकृतियाँ और एनोटेशन बनाना चाह सकते हैं। Google Maps for Compose ऐसा करने के लिए कई कंपोज़ेबल उपलब्ध कराता है, इस पोस्ट में हम Circle
कंपोज़ेबल का उपयोग करने जा रहे हैं।
यदि आपका ऐप उपयोगकर्ता के स्थान से होने वाले परिवर्तनों पर प्रतिक्रिया करने के लिए जियोफ़ेंस का उपयोग करता है, तो वृत्त का उपयोग करना एक अच्छा आकार है। एक वृत्त उस क्षेत्र का प्रतिनिधित्व कर सकता है जिसके भीतर जियोफ़ेंस सक्रिय है।
Box(contentAlignment = Alignment.Center) { GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState ) { Clustering(items = parkMarkers, onClusterClick = { // Handle when the cluster is clicked false }, onClusterItemClick = { marker -> // Handle when a marker in the cluster is clicked selectedMarker = marker false }) } } parkMarkers.forEach { Circle( center = it.position, radius = 120.0, fillColor = Color.Green, strokeColor = Color.Green ) }
यहाँ, हम अपने प्रत्येक मार्कर के लिए एक वृत्त बनाते हैं। वृत्त बनाने में उसे एक स्थिति और वृत्त के लिए त्रिज्या का आकार देना शामिल है। हम सीमा का रंग निर्धारित करने और वृत्त के लिए रंग भरने के लिए दो वैकल्पिक पैरामीटर का भी उपयोग करते हैं।
एक अच्छा नक्शा अक्सर किंवदंतियों और आरेखों के साथ आता है जो यह दिखाते हैं कि नक्शे पर स्थान का माप दूरी के बराबर है। इससे आपको नक्शे में शामिल स्थानों का अंदाजा हो जाता है, क्योंकि हर नक्शा माप के एक ही तरीके का उपयोग नहीं कर सकता है।
डिजिटल मानचित्रों के लिए जो ज़ूम इन और आउट कर सकते हैं, यह जटिलता की एक विशेष परत जोड़ता है क्योंकि दर्शाई गई दूरियाँ गतिशील रूप से बदल सकती हैं। सौभाग्य से, Google मैप्स फॉर कंपोज आपके लिए मददगार है।
विजेट लाइब्रेरी का उपयोग करके, आप DisappearingScaleBar
और ScaleBar
कंपोज़ेबल तक पहुँच प्राप्त करते हैं। ये UI घटक हैं जो मानचित्र के शीर्ष पर बैठते हैं, जो उपयोगकर्ताओं को दूरी का एक माप प्रदान करते हैं जो ज़ूम स्तर के आधार पर बदलता है।
Box(contentAlignment = Alignment.Center) { GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState ) { // You can also use ScaleBar DisappearingScaleBar( modifier = Modifier .padding(top = 5.dp, end = 15.dp) .align(Alignment.TopStart), cameraPositionState = cameraPositionState ) Clustering(items = parkMarkers, onClusterClick = { // Handle when the cluster is clicked false }, onClusterItemClick = { marker -> // Handle when a marker in the cluster is clicked selectedMarker = marker false }) } } parkMarkers.forEach { Circle( center = it.position, radius = 120.0, fillColor = Color.Green, strokeColor = Color.Green ) }
कंपोज़ेबल जोड़ने के बाद, आपको एक स्केलबार मिलता है जो मानचित्र के शीर्ष पर ज़ूम स्तर के आधार पर बदलता है।
Google Maps for Compose, Google Maps के साथ काम करने का एक बेहतरीन तरीका है और इसके बारे में जानने के लिए बहुत कुछ है। अगर आपको मदद की ज़रूरत है, तो मैं यहाँ कुछ जगहों की सलाह देता हूँ: