یک نقشه به برنامه اندروید خود اضافه کنید (Kotlin)

1. قبل از شروع

این کد لبه به شما می آموزد که چگونه Maps SDK برای اندروید را با برنامه خود ادغام کنید و از ویژگی های اصلی آن با ساختن برنامه ای استفاده کنید که نقشه ای از فروشگاه های دوچرخه را در سانفرانسیسکو، کالیفرنیا، ایالات متحده نشان می دهد.

f05e1ca27ff42bf6.png

پیش نیازها

  • دانش اولیه کاتلین و توسعه اندروید

کاری که خواهی کرد

  • Maps SDK for Android را برای افزودن Google Maps به برنامه Android فعال کرده و از آن استفاده کنید.
  • اضافه کردن، سفارشی کردن، و نشانگرهای خوشه.
  • چند خطوط و چند ضلعی ها را روی نقشه بکشید.
  • زاویه دید دوربین را به صورت برنامه ای کنترل کنید.

آنچه شما نیاز دارید

2. راه اندازی شوید

برای مرحله فعال سازی زیر، باید Maps SDK برای Android را فعال کنید.

پلتفرم نقشه های گوگل را راه اندازی کنید

اگر قبلاً حساب Google Cloud Platform و پروژه‌ای با صورت‌حساب فعال ندارید، لطفاً راهنمای شروع به کار با Google Maps Platform را برای ایجاد یک حساب صورت‌حساب و یک پروژه ببینید.

  1. در Cloud Console ، روی منوی کشویی پروژه کلیک کنید و پروژه ای را که می خواهید برای این کد لبه استفاده کنید انتخاب کنید.

  1. APIها و SDKهای پلتفرم Google Maps مورد نیاز برای این لبه کد را در Google Cloud Marketplace فعال کنید. برای انجام این کار، مراحل این ویدئو یا این مستند را دنبال کنید.
  2. یک کلید API در صفحه Credentials در Cloud Console ایجاد کنید. می توانید مراحل این ویدئو یا این مستند را دنبال کنید. همه درخواست‌ها به پلتفرم نقشه‌های Google به یک کلید API نیاز دارند.

3. شروع سریع

برای شروع هر چه سریع‌تر، در اینجا چند کد شروع وجود دارد که به شما کمک می‌کند تا این نرم‌افزار را دنبال کنید. از شما استقبال می شود که به سراغ راه حل بروید، اما اگر می خواهید تمام مراحل ساخت آن را خودتان دنبال کنید، به خواندن ادامه دهید.

  1. اگر git را نصب کرده اید، مخزن را کلون کنید.
git clone https://github.com/googlecodelabs/maps-platform-101-android.git

همچنین می‌توانید روی دکمه زیر کلیک کنید تا کد منبع را دانلود کنید.

  1. پس از دریافت کد، ادامه دهید و پروژه موجود در دایرکتوری starter را در Android Studio باز کنید.

4. نقشه های گوگل را اضافه کنید

در این بخش، نقشه های گوگل را اضافه می کنید تا با راه اندازی برنامه بارگذاری شود.

d1d068b5d4ae38b9.png

کلید API خود را اضافه کنید

کلید API که در مرحله قبل ایجاد کردید باید به برنامه ارائه شود تا Maps SDK برای Android بتواند کلید شما را با برنامه شما مرتبط کند.

  1. برای ارائه این، فایلی به نام local.properties را در فهرست اصلی پروژه خود باز کنید (همان سطحی که gradle.properties و settings.gradle هستند).
  2. در آن فایل، یک کلید جدید GOOGLE_MAPS_API_KEY تعریف کنید که مقدار آن کلید API است که ایجاد کرده‌اید.

محلی.ملاک

GOOGLE_MAPS_API_KEY=YOUR_KEY_HERE

توجه داشته باشید که local.properties در فایل local.properties در مخزن Git فهرست شده است .gitignore این به این دلیل است که کلید API شما اطلاعات حساسی محسوب می‌شود و در صورت امکان نباید در کنترل منبع بررسی شود.

  1. در مرحله بعد، برای افشای API خود تا بتوان از آن در سراسر برنامه استفاده کرد، افزونه Secrets Gradle برای Android را در فایل build.gradle برنامه خود واقع در فهرست app/ قرار دهید و خط زیر را در بلوک plugins اضافه کنید:

build.gradle سطح برنامه

plugins {
    // ...
    id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
}

همچنین باید فایل build.gradle در سطح پروژه خود را تغییر دهید تا مسیر کلاس زیر را شامل شود:

build.gradle در سطح پروژه

buildscript {
    dependencies {
        // ...
        classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:1.3.0"
    }
}

این افزونه کلیدهایی را که در فایل local.properties خود تعریف کرده اید به عنوان متغیرهای ساخت در فایل مانیفست اندروید و به عنوان متغیر در کلاس BuildConfig تولید شده توسط Gradle در زمان ساخت در دسترس قرار می دهد. با استفاده از این افزونه، کد boilerplate که در غیر این صورت برای خواندن ویژگی‌ها از local.properties بود، حذف می‌شود تا بتوان به آن در سراسر برنامه دسترسی داشت.

وابستگی نقشه های گوگل را اضافه کنید

  1. اکنون که کلید API شما در داخل برنامه قابل دسترسی است، گام بعدی این است که وابستگی Maps SDK برای Android را به فایل build.gradle برنامه خود اضافه کنید.

در پروژه شروع که با این کد لبه ارائه می شود، این وابستگی قبلاً برای شما اضافه شده است.

build.gradle

dependencies {
   // Dependency to include Maps SDK for Android
   implementation 'com.google.android.gms:play-services-maps:17.0.0'
}
  1. در مرحله بعد، یک meta-data جدید در AndroidManifest.xml اضافه کنید تا کلید API را که در مرحله قبل ایجاد کرده‌اید ارسال کنید. برای انجام این کار، ادامه دهید و این فایل را در Android Studio باز کنید و تگ meta-data زیر را در داخل شی application در فایل AndroidManifest.xml خود که در app/src/main قرار دارد، اضافه کنید.

AndroidManifest.xml

<meta-data
   android:name="com.google.android.geo.API_KEY"
   android:value="${GOOGLE_MAPS_API_KEY}" />
  1. سپس یک فایل طرح بندی جدید به نام activity_main.xml در پوشه app/src/main/res/layout/ ایجاد کنید و آن را به صورت زیر تعریف کنید:

activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity">

   <fragment
       class="com.google.android.gms.maps.SupportMapFragment"
       android:id="@+id/map_fragment"
       android:layout_width="match_parent"
       android:layout_height="match_parent" />

</FrameLayout>

این طرح بندی دارای یک SupportMapFragment FrameLayout . این قطعه شامل شی GoogleMaps زیرین است که در مراحل بعدی استفاده می کنید.

  1. در نهایت، کلاس MainActivity واقع در app/src/main/java/com/google/codelabs/buildyourfirstmap با اضافه کردن کد زیر برای لغو روش onCreate به‌روزرسانی کنید تا بتوانید محتوای آن را با طرح‌بندی جدیدی که ایجاد کرده‌اید تنظیم کنید.

فعالیت اصلی

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.activity_main)
}
  1. حالا ادامه دهید و برنامه را اجرا کنید. اکنون باید بارگذاری نقشه را روی صفحه دستگاه خود مشاهده کنید.

5. طراحی نقشه مبتنی بر ابر (اختیاری)

می توانید سبک نقشه خود را با استفاده از استایل نقشه مبتنی بر ابر سفارشی کنید.

یک شناسه نقشه ایجاد کنید

اگر هنوز شناسه نقشه با سبک نقشه مرتبط با آن ایجاد نکرده‌اید، برای تکمیل مراحل زیر، راهنمای Map IDs را ببینید:

  1. یک شناسه نقشه ایجاد کنید.
  2. شناسه نقشه را به سبک نقشه مرتبط کنید.

افزودن شناسه نقشه به برنامه شما

برای استفاده از شناسه نقشه ای که ایجاد کرده اید، فایل activity_main.xml را تغییر دهید و شناسه نقشه خود را در ویژگی map:mapId از SupportMapFragment قرار دهید.

activity_main.xml

<fragment xmlns:map="http://schemas.android.com/apk/res-auto"
    class="com.google.android.gms.maps.SupportMapFragment"
    <!-- ... -->
    map:mapId="YOUR_MAP_ID" />

پس از تکمیل این کار، برنامه را اجرا کنید تا نقشه خود را به سبکی که انتخاب کرده اید ببینید!

6. نشانگرها را اضافه کنید

در این کار، نشانگرهایی را به نقشه اضافه می کنید که نشان دهنده نقاط مورد علاقه شما هستند که می خواهید روی نقشه برجسته شوند. ابتدا لیستی از مکان هایی که در پروژه شروع کننده برای شما ارائه شده است را بازیابی می کنید، سپس آن مکان ها را به نقشه اضافه می کنید. در این مثال، اینها مغازه های دوچرخه هستند.

bc5576877369b554.png

یک مرجع به GoogleMap دریافت کنید

ابتدا باید یک مرجع به شی GoogleMap بدست آورید تا بتوانید از روش های آن استفاده کنید. برای انجام این کار، کد زیر را در متد MainActivity.onCreate() خود بلافاصله پس از فراخوانی setContentView() اضافه کنید:

MainActivity.onCreate()

val mapFragment = supportFragmentManager.findFragmentById(   
    R.id.map_fragment
) as? SupportMapFragment
mapFragment?.getMapAsync { googleMap ->
    addMarkers(googleMap)
}

پیاده سازی ابتدا SupportMapFragment را که در مرحله قبل با استفاده از findFragmentById() در شی SupportFragmentManager اضافه کردید، پیدا می کند. هنگامی که یک مرجع به دست آمد، getMapAsync() فراخوانی می شود و سپس در یک لامبدا ارسال می شود. این لامبدا جایی است که شی GoogleMap می شود. در داخل این لامبدا، فراخوانی متد addMarkers() فراخوانی می شود که به زودی تعریف می شود.

کلاس ارائه شده: PlacesReader

در پروژه استارتر کلاس PlacesReader برای شما در نظر گرفته شده است. این کلاس لیستی از 49 مکان را می خواند که در یک فایل JSON به نام places.json ذخیره شده اند و آنها را به عنوان List<Place> برمی گرداند. این مکان‌ها فهرستی از دوچرخه‌فروشی‌های اطراف سانفرانسیسکو، کالیفرنیا، ایالات متحده را نشان می‌دهند.

اگر در مورد اجرای این کلاس کنجکاو هستید، می توانید در GitHub به آن دسترسی داشته باشید یا کلاس PlacesReader را در Android Studio باز کنید.

PlacesReader

package com.google.codelabs.buildyourfirstmap.place

import android.content.Context
import com.google.codelabs.buildyourfirstmap.R
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import java.io.InputStream
import java.io.InputStreamReader

/**
* Reads a list of place JSON objects from the file places.json
*/
class PlacesReader(private val context: Context) {

   // GSON object responsible for converting from JSON to a Place object
   private val gson = Gson()

   // InputStream representing places.json
   private val inputStream: InputStream
       get() = context.resources.openRawResource(R.raw.places)

   /**
    * Reads the list of place JSON objects in the file places.json
    * and returns a list of Place objects
    */
   fun read(): List<Place> {
       val itemType = object : TypeToken<List<PlaceResponse>>() {}.type
       val reader = InputStreamReader(inputStream)
       return gson.fromJson<List<PlaceResponse>>(reader, itemType).map {
           it.toPlace()
       }
   }

مکان ها را بارگیری کنید

برای بارگذاری لیست دوچرخه‌فروشی‌ها، یک ویژگی به نام places در MainActivity اضافه کنید و آن را به صورت زیر تعریف کنید:

MainActivity.places

private val places: List<Place> by lazy {
   PlacesReader(this).read()
}

این کد متد read() را در PlacesReader فراخوانی می کند که یک List<Place> برمی گرداند. یک Place دارای یک ویژگی به name ، نام مکان و یک latLng - مختصاتی که مکان در آن قرار دارد.

محل

data class Place(
   val name: String,
   val latLng: LatLng,
   val address: LatLng,
   val rating: Float
)

نشانگرها را به نقشه اضافه کنید

اکنون که لیست مکان ها در حافظه بارگذاری شده است، مرحله بعدی نمایش این مکان ها روی نقشه است.

  1. یک متد در MainActivity به نام addMarkers() ایجاد کنید و آن را به صورت زیر تعریف کنید:

MainActivity.addMarkers()

/**
* Adds marker representations of the places list on the provided GoogleMap object
*/
private fun addMarkers(googleMap: GoogleMap) {
   places.forEach { place ->
       val marker = googleMap.addMarker(
           MarkerOptions()
               .title(place.name)
               .position(place.latLng)
       )
   }
}

این روش از طریق لیست places و به دنبال آن فراخوانی addMarker() در شیء ارائه شده GoogleMap تکرار می شود. نشانگر با نمونه سازی یک شی MarkerOptions ایجاد می شود که به شما امکان می دهد خود نشانگر را سفارشی کنید. در این حالت عنوان و موقعیت نشانگر ارائه می شود که به ترتیب نشان دهنده نام فروشگاه دوچرخه و مختصات آن است.

  1. ادامه دهید و برنامه را اجرا کنید و به سانفرانسیسکو بروید تا نشانگرهایی را که به تازگی اضافه کرده اید ببینید!

7. نشانگرها را سفارشی کنید

چندین گزینه سفارشی‌سازی برای نشانگرها وجود دارد که به تازگی اضافه کرده‌اید تا به آنها کمک کنید برجسته شوند و اطلاعات مفیدی را به کاربران منتقل کنند. در این کار، با سفارشی کردن تصویر هر نشانگر و همچنین پنجره اطلاعاتی که هنگام ضربه زدن روی یک نشانگر نمایش داده می‌شود، برخی از آن‌ها را بررسی خواهید کرد.

a26f82802fe838e9.png

افزودن پنجره اطلاعات

به‌طور پیش‌فرض، وقتی روی نشانگر ضربه می‌زنید، پنجره اطلاعات عنوان و قطعه آن را نمایش می‌دهد (در صورت تنظیم). شما این را سفارشی می کنید تا بتواند اطلاعات اضافی مانند آدرس و رتبه مکان را نمایش دهد.

marker_info_contents.xml را ایجاد کنید

ابتدا یک فایل طرح بندی جدید به نام marker_info_contents.xml ایجاد کنید.

  1. برای انجام این کار، روی پوشه app/src/main/res/layout در نمای پروژه در Android Studio کلیک راست کرده و New > Layout Resource File را انتخاب کنید.

8cac51fcbef9171b.png

  1. در کادر گفتگو، marker_info_contents را در قسمت File name و LinearLayout را در قسمت Root element تایپ کنید، سپس روی OK کلیک کنید.

8783af12baf07a80.png

این فایل طرح بندی بعداً برای نمایش محتویات داخل پنجره اطلاعات باد می شود.

  1. محتویات قطعه کد زیر را کپی کنید، که سه TextViews در یک گروه نمای LinearLayout عمودی اضافه می کند، و کد پیش فرض را در فایل بازنویسی کنید.

marker_info_contents.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:orientation="vertical"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:gravity="center_horizontal"
   android:padding="8dp">

   <TextView
       android:id="@+id/text_view_title"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:textColor="@android:color/black"
       android:textSize="18sp"
       android:textStyle="bold"
       tools:text="Title"/>

   <TextView
       android:id="@+id/text_view_address"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:textColor="@android:color/black"
       android:textSize="16sp"
       tools:text="123 Main Street"/>

   <TextView
       android:id="@+id/text_view_rating"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:textColor="@android:color/black"
       android:textSize="16sp"
       tools:text="Rating: 3"/>

</LinearLayout>

یک پیاده سازی از یک InfoWindowAdapter ایجاد کنید

پس از ایجاد فایل layout برای پنجره اطلاعات سفارشی، مرحله بعدی پیاده سازی رابط GoogleMap.InfoWindowAdapter است. این رابط شامل دو متد getInfoWindow() و getInfoContents() می باشد. هر دو روش یک شی View اختیاری را برمی‌گردانند که در آن اولی برای سفارشی کردن خود پنجره استفاده می‌شود، در حالی که دومی برای سفارشی کردن محتویات آن است. در مورد شما، شما هر دو را پیاده‌سازی می‌کنید و بازگشت getInfoContents() را سفارشی می‌کنید در حالی که در getInfoWindow() null را برمی‌گردانید، که نشان می‌دهد باید از پنجره پیش‌فرض استفاده شود.

  1. با کلیک راست روی پوشه app/src/main/java/com/google/codelabs/buildyourfirstmap در نمای پروژه در Android Studio، یک فایل Kotlin جدید به نام MarkerInfoWindowAdapter در همان بسته MainActivity ایجاد کنید، سپس New > Kotlin File/Class را انتخاب کنید. .

3975ba36eba9f8e1.png

  1. در گفتگو، MarkerInfoWindowAdapter را تایپ کنید و File را برجسته نگه دارید.

992235af53d3897f.png

  1. پس از ایجاد فایل، محتوای موجود در قطعه کد زیر را در فایل جدید خود کپی کنید.

MarkerInfoWindowAdapter

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.Marker
import com.google.codelabs.buildyourfirstmap.place.Place

class MarkerInfoWindowAdapter(
    private val context: Context
) : GoogleMap.InfoWindowAdapter {
   override fun getInfoContents(marker: Marker?): View? {
       // 1. Get tag
       val place = marker?.tag as? Place ?: return null

       // 2. Inflate view and set title, address, and rating
       val view = LayoutInflater.from(context).inflate(
           R.layout.marker_info_contents, null
       )
       view.findViewById<TextView>(
           R.id.text_view_title
       ).text = place.name
       view.findViewById<TextView>(
           R.id.text_view_address
       ).text = place.address
       view.findViewById<TextView>(
           R.id.text_view_rating
       ).text = "Rating: %.2f".format(place.rating)

       return view
   }

   override fun getInfoWindow(marker: Marker?): View? {
       // Return null to indicate that the 
       // default window (white bubble) should be used
       return null
   }
}

در محتویات getInfoContents() ، نشانگر ارائه شده در متد به نوع Place فرستاده می‌شود و اگر امکان ارسال امکان‌پذیر نباشد، متد null را برمی‌گرداند (شما هنوز خاصیت برچسب را روی Marker تنظیم نکرده‌اید، اما این کار را در مرحله بعد انجام دهید).

سپس، layout marker_info_contents.xml باد می‌شود و سپس متن حاوی TextViews را روی برچسب Place تنظیم می‌کنیم.

MainActivity را به روز کنید

برای چسباندن تمام اجزایی که تاکنون ایجاد کرده اید، باید دو خط در کلاس MainActivity خود اضافه کنید.

ابتدا، برای ارسال InfoWindowAdapter سفارشی، MarkerInfoWindowAdapter ، در فراخوانی متد getMapAsync ، متد setInfoWindowAdapter() را در شیء GoogleMap فراخوانی کنید و یک نمونه جدید از MarkerInfoWindowAdapter ایجاد کنید.

  1. این کار را با افزودن کد زیر پس از addMarkers() متد addMarkers در داخل getMapAsync() lambda انجام دهید.

MainActivity.onCreate()

// Set custom info window adapter
googleMap.setInfoWindowAdapter(MarkerInfoWindowAdapter(this))

در نهایت، باید هر مکان را به عنوان ویژگی برچسب روی هر نشانگری که به نقشه اضافه می‌شود، تنظیم کنید.

  1. برای انجام این کار، places.forEach{} را در تابع addMarkers() با موارد زیر تغییر دهید:

MainActivity.addMarkers()

places.forEach { place ->
   val marker = googleMap.addMarker(
       MarkerOptions()
           .title(place.name)
           .position(place.latLng)
           .icon(bicycleIcon)
   )

   // Set place as the tag on the marker object so it can be referenced within
   // MarkerInfoWindowAdapter
   marker.tag = place
}

یک تصویر نشانگر سفارشی اضافه کنید

سفارشی کردن تصویر نشانگر یکی از راه های سرگرم کننده برای ارتباط با نوع مکانی است که نشانگر روی نقشه شما نشان می دهد. برای این مرحله، دوچرخه‌ها را به جای نشانگرهای قرمز پیش‌فرض نمایش می‌دهید تا هر مغازه را روی نقشه نشان دهد. پروژه شروع کننده شامل نماد دوچرخه ic_directions_bike_black_24dp.xml در app/src/res/drawable است که شما از آن استفاده می کنید.

6eb7358bb61b0a88.png

بیت مپ سفارشی را روی نشانگر تنظیم کنید

با در اختیار داشتن نماد دوچرخه قابل ترسیم برداری، گام بعدی این است که آن قابل ترسیم را به عنوان نماد هر نشانگر روی نقشه تنظیم کنید. MarkerOptions یک icon متد دارد که یک BitmapDescriptor را که برای انجام این کار استفاده می‌کنید، وارد می‌کند.

ابتدا باید وکتور قابل ترسیمی را که به تازگی اضافه کرده اید به BitmapDescriptor کنید. فایلی به نام BitMapHelper که در پروژه شروع کننده گنجانده شده است حاوی یک تابع کمکی به نام vectorToBitmap() است که دقیقاً این کار را انجام می دهد.

BitmapHelper

package com.google.codelabs.buildyourfirstmap

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.util.Log
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.DrawableCompat
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.BitmapDescriptorFactory

object BitmapHelper {
   /**
    * Demonstrates converting a [Drawable] to a [BitmapDescriptor], 
    * for use as a marker icon. Taken from ApiDemos on GitHub:
    * https://github.com/googlemaps/android-samples/blob/main/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/MarkerDemoActivity.kt
    */
   fun vectorToBitmap(
      context: Context,
      @DrawableRes id: Int, 
      @ColorInt color: Int
   ): BitmapDescriptor {
       val vectorDrawable = ResourcesCompat.getDrawable(context.resources, id, null)
       if (vectorDrawable == null) {
           Log.e("BitmapHelper", "Resource not found")
           return BitmapDescriptorFactory.defaultMarker()
       }
       val bitmap = Bitmap.createBitmap(
           vectorDrawable.intrinsicWidth,
           vectorDrawable.intrinsicHeight,
           Bitmap.Config.ARGB_8888
       )
       val canvas = Canvas(bitmap)
       vectorDrawable.setBounds(0, 0, canvas.width, canvas.height)
       DrawableCompat.setTint(vectorDrawable, color)
       vectorDrawable.draw(canvas)
       return BitmapDescriptorFactory.fromBitmap(bitmap)
   }
}

این روش یک Context ، یک شناسه منبع قابل ترسیم و همچنین یک عدد صحیح رنگی را می گیرد و یک نمایش BitmapDescriptor از آن ایجاد می کند.

با استفاده از متد helper، یک ویژگی جدید به نام bicycleIcon کنید و تعریف زیر را به آن بدهید: MainActivity.bicycleIcon

private val bicycleIcon: BitmapDescriptor by lazy {
   val color = ContextCompat.getColor(this, R.color.colorPrimary)
   BitmapHelper.vectorToBitmap(this, R.drawable.ic_directions_bike_black_24dp, color)
}

این ویژگی از رنگ از پیش تعریف شده colorPrimary در برنامه شما استفاده می کند و از آن برای رنگ آمیزی نماد دوچرخه و برگرداندن آن به عنوان BitmapDescriptor استفاده می کند.

  1. با استفاده از این ویژگی، ادامه دهید و متد icon MarkerOptions را در addMarkers() فراخوانی کنید تا سفارشی سازی آیکون خود را تکمیل کنید. با انجام این کار، ویژگی نشانگر باید به شکل زیر باشد:

MainActivity.addMarkers()

val marker = googleMap.addMarker(
    MarkerOptions()
        .title(place.name)
        .position(place.latLng)
        .icon(bicycleIcon)
)
  1. برنامه را اجرا کنید تا نشانگرهای به روز شده را ببینید!

8. نشانگرهای خوشه ای

بسته به اینکه چقدر روی نقشه زوم می کنید، ممکن است متوجه شده باشید که نشانگرهایی که اضافه کرده اید همپوشانی دارند. تعامل با نشانگرهای همپوشانی بسیار سخت است و نویز زیادی ایجاد می کند که بر قابلیت استفاده برنامه شما تأثیر می گذارد.

68591edc86d73724.png

برای بهبود تجربه کاربر برای این کار، هر زمان که مجموعه داده بزرگی دارید که از نزدیک خوشه‌بندی شده است، بهترین روش اجرای خوشه‌بندی نشانگر است. با خوشه‌بندی، وقتی نقشه را بزرگ‌نمایی و بزرگنمایی می‌کنید، نشانگرهایی که در مجاورت یکدیگر قرار دارند به این صورت در کنار هم قرار می‌گیرند:

f05e1ca27ff42bf6.png

برای اجرای این کار، به کمک Maps SDK for Android Utility Library نیاز دارید.

Maps SDK for Android Utility Library

Maps SDK for Android Utility Library به عنوان راهی برای گسترش عملکرد Maps SDK برای Android ایجاد شد. ویژگی‌های پیشرفته‌ای مانند خوشه‌بندی نشانگر، نقشه‌های حرارتی، پشتیبانی KML و GeoJson، کدگذاری و رمزگشایی چند خطی، و تعداد کمی از توابع کمکی در اطراف هندسه کروی را ارائه می‌دهد.

build.gradle خود را به روز کنید

از آنجایی که کتابخانه ابزار به طور جداگانه از Maps SDK برای Android بسته بندی شده است، باید یک وابستگی اضافی به فایل build.gradle خود اضافه کنید.

  1. ادامه دهید و بخش dependencies ها را در فایل app/build.gradle خود به روز کنید.

build.gradle

implementation 'com.google.maps.android:android-maps-utils:1.1.0'
  1. پس از افزودن این خط، باید همگام سازی پروژه را برای واکشی وابستگی های جدید انجام دهید.

b7b030ec82c007fd.png

اجرای خوشه بندی

برای پیاده سازی خوشه بندی در برنامه خود، این سه مرحله را دنبال کنید:

  1. رابط ClusterItem را پیاده سازی کنید.
  2. کلاس DefaultClusterRenderer را زیر کلاس قرار دهید.
  3. یک ClusterManager ایجاد کنید و موارد را اضافه کنید.

رابط ClusterItem را پیاده سازی کنید

تمام اشیایی که نشانگر خوشه‌ای را روی نقشه نشان می‌دهند باید رابط ClusterItem را پیاده‌سازی کنند. در مورد شما، این بدان معناست که مدل Place باید با ClusterItem مطابقت داشته باشد. ادامه دهید و فایل Place.kt را باز کنید و تغییرات زیر را در آن انجام دهید:

محل

data class Place(
   val name: String,
   val latLng: LatLng,
   val address: String,
   val rating: Float
) : ClusterItem {
   override fun getPosition(): LatLng =
       latLng

   override fun getTitle(): String =
       name

   override fun getSnippet(): String =
       address
}

ClusterItem این سه روش را تعریف می کند:

  • getPosition() که نشان دهنده LatLng مکان است.
  • getTitle() که نشان دهنده نام مکان است
  • getSnippet() که نشان دهنده آدرس مکان است.

کلاس DefaultClusterRenderer را زیر کلاس قرار دهید

کلاسی که وظیفه اجرای خوشه بندی را بر عهده دارد، ClusterManager ، به صورت داخلی از یک کلاس ClusterRenderer برای مدیریت ایجاد خوشه ها در حین حرکت و زوم در اطراف نقشه استفاده می کند. به‌طور پیش‌فرض، رندر پیش‌فرض، DefaultClusterRenderer ، ارائه می‌شود که ClusterRenderer را پیاده‌سازی می‌کند. برای موارد ساده، این باید کافی باشد. اما در مورد شما، چون نشانگرها باید سفارشی شوند، باید این کلاس را گسترش دهید و سفارشی‌سازی‌ها را در آنجا اضافه کنید.

ادامه دهید و فایل Kotlin PlaceRenderer.kt را در بسته com.google.codelabs.buildyourfirstmap.place ایجاد کنید و آن را به صورت زیر تعریف کنید:

PlaceRenderer

package com.google.codelabs.buildyourfirstmap.place

import android.content.Context
import androidx.core.content.ContextCompat
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.MarkerOptions
import com.google.codelabs.buildyourfirstmap.BitmapHelper
import com.google.codelabs.buildyourfirstmap.R
import com.google.maps.android.clustering.ClusterManager
import com.google.maps.android.clustering.view.DefaultClusterRenderer

/**
* A custom cluster renderer for Place objects.
*/
class PlaceRenderer(
   private val context: Context,
   map: GoogleMap,
   clusterManager: ClusterManager<Place>
) : DefaultClusterRenderer<Place>(context, map, clusterManager) {

   /**
    * The icon to use for each cluster item
    */
   private val bicycleIcon: BitmapDescriptor by lazy {
       val color = ContextCompat.getColor(context,
           R.color.colorPrimary
       )
       BitmapHelper.vectorToBitmap(
           context,
           R.drawable.ic_directions_bike_black_24dp,
           color
       )
   }

   /**
    * Method called before the cluster item (the marker) is rendered.
    * This is where marker options should be set.
    */
   override fun onBeforeClusterItemRendered(
      item: Place,
      markerOptions: MarkerOptions
   ) {
       markerOptions.title(item.name)
           .position(item.latLng)
           .icon(bicycleIcon)
   }

   /**
    * Method called right after the cluster item (the marker) is rendered.
    * This is where properties for the Marker object should be set.
    */
   override fun onClusterItemRendered(clusterItem: Place, marker: Marker) {
       marker.tag = clusterItem
   }
}

این کلاس این دو تابع را لغو می کند:

  • onBeforeClusterItemRendered() که قبل از رندر شدن خوشه روی نقشه فراخوانی می شود. در اینجا، می‌توانید سفارشی‌سازی‌ها را از طریق MarkerOptions ارائه دهید — در این مورد، عنوان، موقعیت و نماد نشانگر را تعیین می‌کند.
  • onClusterItemRenderer() که بلافاصله پس از رندر شدن نشانگر روی نقشه فراخوانی می شود. اینجاست که می توانید به شیء ایجاد شده Marker دسترسی داشته باشید—در این مورد، ویژگی تگ نشانگر را تنظیم می کند.

یک ClusterManager ایجاد کنید و موارد را اضافه کنید

در نهایت، برای اینکه خوشه‌بندی کار کند، باید MainActivity را تغییر دهید تا یک ClusterManager را نمونه‌سازی کنید و وابستگی‌های لازم را برای آن فراهم کنید. ClusterManager اضافه کردن نشانگرها (اشیاء ClusterItem ) را به صورت داخلی کنترل می کند، بنابراین به جای اضافه کردن نشانگرها به طور مستقیم بر روی نقشه، این مسئولیت به ClusterManager محول می شود. علاوه بر این، ClusterManager همچنین setInfoWindowAdapter() را به صورت داخلی فراخوانی می کند، بنابراین تنظیم یک پنجره اطلاعات سفارشی باید روی شی MarkerManager.Collection ClusterManger انجام شود.

  1. برای شروع، محتویات لامبدا را در getMapAsync() در MainActivity.onCreate() تغییر دهید. ادامه دهید و فراخوانی را با addMarkers() و setInfoWindowAdapter() ، و به جای آن متدی به نام addClusteredMarkers() را فراخوانی کنید که در ادامه آن را تعریف می کنید.

MainActivity.onCreate()

mapFragment?.getMapAsync { googleMap ->
    //addMarkers(googleMap)
    addClusteredMarkers(googleMap)

    // Set custom info window adapter.
    // googleMap.setInfoWindowAdapter(MarkerInfoWindowAdapter(this))
}
  1. سپس، در MainActivity ، addClusteredMarkers() تعریف کنید.

MainActivity.addClusteredMarkers()

/**
* Adds markers to the map with clustering support.
*/
private fun addClusteredMarkers(googleMap: GoogleMap) {
   // Create the ClusterManager class and set the custom renderer.
   val clusterManager = ClusterManager<Place>(this, googleMap)
   clusterManager.renderer =
       PlaceRenderer(
           this,
           googleMap,
           clusterManager
       )

   // Set custom info window adapter
   clusterManager.markerCollection.setInfoWindowAdapter(MarkerInfoWindowAdapter(this))

   // Add the places to the ClusterManager.
   clusterManager.addItems(places)
   clusterManager.cluster()

   // Set ClusterManager as the OnCameraIdleListener so that it
   // can re-cluster when zooming in and out.
   googleMap.setOnCameraIdleListener {
       clusterManager.onCameraIdle()
   }
}

این متد یک ClusterManager را نمونه‌سازی می‌کند، رندر سفارشی PlacesRenderer را به آن ارسال می‌کند، همه مکان‌ها را اضافه می‌کند و متد cluster() را فراخوانی می‌کند. همچنین، از آنجایی که ClusterManager از setInfoWindowAdapter() روی شی نقشه استفاده می کند، تنظیم پنجره اطلاعات سفارشی باید روی شی ClusterManager.markerCollection انجام شود. در نهایت، چون می‌خواهید هنگام حرکت کاربر و بزرگ‌نمایی در اطراف نقشه، خوشه‌بندی تغییر کند، یک OnCameraIdleListener برای googleMap ارائه می‌شود، به طوری که وقتی دوربین بی‌کار می‌شود، clusterManager.onCameraIdle() فراخوانی می‌شود.

  1. ادامه دهید و برنامه را اجرا کنید تا فروشگاه های خوشه ای جدید را ببینید!

9. روی نقشه بکشید

در حالی که قبلاً یک راه را برای ترسیم روی نقشه (با افزودن نشانگرها) بررسی کرده اید، Maps SDK برای Android از روش های متعدد دیگری برای نمایش اطلاعات مفید روی نقشه پشتیبانی می کند.

برای مثال، اگر می‌خواهید مسیرها و مناطق را روی نقشه نشان دهید، می‌توانید از چند خط و چند ضلعی برای نمایش آن‌ها روی نقشه استفاده کنید. یا اگر می‌خواهید تصویری را روی سطح زمین ثابت کنید، می‌توانید از پوشش‌های زمینی استفاده کنید.

در این کار، یاد می‌گیرید که چگونه شکل‌ها، به‌ویژه یک دایره را در اطراف یک نشانگر هر زمان که ضربه بزنید، بکشید.

f98ce13055430352.png

شنونده کلیک را اضافه کنید

به طور معمول، راهی که می‌توانید یک کلیک شنونده را به یک نشانگر اضافه کنید، ارسال یک کلیک شنونده به طور مستقیم روی شی GoogleMap از طریق setOnMarkerClickListener() است. با این حال، از آنجایی که شما از خوشه بندی استفاده می کنید، شنونده کلیک باید به ClusterManager ارائه شود.

  1. در addClusteredMarkers() در MainActivity ، ادامه دهید و خط زیر را درست بعد از فراخوانی به cluster() اضافه کنید.

MainActivity.addClusteredMarkers()

// Show polygon
clusterManager.setOnClusterItemClickListener { item ->
   addCircle(googleMap, item)
   return@setOnClusterItemClickListener false
}

این متد یک شنونده اضافه می کند و متد addCircle() را فراخوانی می کند که در ادامه آن را تعریف می کنید. در نهایت، false از این روش برگردانده می شود تا نشان دهد که این روش این رویداد را مصرف نکرده است.

  1. در مرحله بعد، باید circle ویژگی و متد addCircle() را در MainActivity تعریف کنید.

MainActivity.addCircle()

private var circle: Circle? = null

/**
* Adds a [Circle] around the provided [item]
*/
private fun addCircle(googleMap: GoogleMap, item: Place) {
   circle?.remove()
   circle = googleMap.addCircle(
       CircleOptions()
           .center(item.latLng)
           .radius(1000.0)
           .fillColor(ContextCompat.getColor(this, R.color.colorPrimaryTranslucent))
           .strokeColor(ContextCompat.getColor(this, R.color.colorPrimary))
   )
}

ویژگی circle به گونه ای تنظیم شده است که هر زمان که روی نشانگر جدیدی ضربه می زند، دایره قبلی حذف شده و یک نشانگر جدید اضافه می شود. توجه داشته باشید که API برای افزودن یک دایره کاملاً شبیه به اضافه کردن یک نشانگر است.

  1. همین حالا بروید و برنامه را اجرا کنید تا تغییرات را ببینید.

10. کنترل دوربین

به عنوان آخرین کار خود، به برخی از کنترل های دوربین نگاه می کنید تا بتوانید نمای اطراف یک منطقه خاص را متمرکز کنید.

دوربین و نمای

اگر متوجه شدید که هنگام اجرای برنامه، دوربین قاره آفریقا را نمایش می‌دهد، و باید با زحمت به سانفرانسیسکو زوم کنید تا نشانگرهایی را که اضافه کرده‌اید پیدا کنید. در حالی که می تواند یک راه سرگرم کننده برای کاوش در جهان باشد، اگر بخواهید فورا نشانگرها را نمایش دهید مفید نیست.

برای کمک به این کار، می‌توانید موقعیت دوربین را به‌صورت برنامه‌ای تنظیم کنید تا نما در مرکز آن جایی که می‌خواهید قرار گیرد.

  1. ادامه دهید و کد زیر را به getMapAsync() اضافه کنید تا نمای دوربین را به گونه‌ای تنظیم کنید که هنگام راه‌اندازی برنامه به سانفرانسیسکو راه‌اندازی شود.

MainActivity.onCreate()

mapFragment?.getMapAsync { googleMap ->
   // Ensure all places are visible in the map.
   googleMap.setOnMapLoadedCallback {
       val bounds = LatLngBounds.builder()
       places.forEach { bounds.include(it.latLng) }
       googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), 20))
   }
}

ابتدا، setOnMapLoadedCallback() فراخوانی می شود تا آپدیت دوربین فقط پس از بارگیری نقشه انجام شود. این مرحله ضروری است زیرا ویژگی های نقشه، مانند ابعاد، قبل از برقراری تماس به روز رسانی دوربین باید محاسبه شوند.

در لامبدا، یک شی LatLngBounds جدید ساخته شده است که یک منطقه مستطیلی را روی نقشه تعریف می کند. این به طور تدریجی با گنجاندن تمام مقادیر LatLng مکان در آن ساخته می شود تا اطمینان حاصل شود که همه مکان ها در داخل کران هستند. هنگامی که این شی ساخته شد، moveCamera() در GoogleMap فراخوانی می شود و CameraUpdate از طریق CameraUpdateFactory.newLatLngBounds(bounds.build(), 20) برای آن ارائه می شود.

  1. برنامه را اجرا کنید و متوجه شوید که دوربین اکنون در سانفرانسیسکو راه اندازی شده است.

گوش دادن به تغییرات دوربین

علاوه بر تغییر موقعیت دوربین، می توانید در حین حرکت کاربر در اطراف نقشه به به روز رسانی های دوربین نیز گوش دهید. این می تواند مفید باشد اگر می خواهید رابط کاربری را در حین حرکت دوربین تغییر دهید.

فقط برای سرگرمی، هر زمان که دوربین جابجا می شود، کد را طوری تغییر می دهید که نشانگرها شفاف شوند.

  1. در addClusteredMarkers() ادامه دهید و خطوط زیر را به انتهای متد اضافه کنید:

MainActivity.addClusteredMarkers()

// When the camera starts moving, change the alpha value of the marker to translucent.
googleMap.setOnCameraMoveStartedListener {
   clusterManager.markerCollection.markers.forEach { it.alpha = 0.3f }
   clusterManager.clusterMarkerCollection.markers.forEach { it.alpha = 0.3f }
}

این یک OnCameraMoveStartedListener اضافه می کند تا هر زمان که دوربین شروع به حرکت کرد، مقادیر آلفای تمام نشانگرها (هم خوشه ها و هم نشانگرها) به 0.3f تغییر می یابد تا نشانگرها نیمه شفاف به نظر برسند.

  1. در نهایت، برای تغییر دادن نشانگرهای نیمه شفاف به حالت مات در هنگام توقف دوربین، محتویات setOnCameraIdleListener در addClusteredMarkers() را به صورت زیر تغییر دهید:

MainActivity.addClusteredMarkers()

googleMap.setOnCameraIdleListener {
   // When the camera stops moving, change the alpha value back to opaque.
   clusterManager.markerCollection.markers.forEach { it.alpha = 1.0f }
   clusterManager.clusterMarkerCollection.markers.forEach { it.alpha = 1.0f }

   // Call clusterManager.onCameraIdle() when the camera stops moving so that reclustering
   // can be performed when the camera stops moving.
   clusterManager.onCameraIdle()
}
  1. ادامه دهید و برنامه را اجرا کنید تا نتایج را ببینید!

11. نقشه های KTX

برای برنامه‌های Kotlin که از یک یا چند SDK Android پلتفرم نقشه‌های Google استفاده می‌کنند، افزونه Kotlin یا کتابخانه‌های KTX در دسترس هستند تا شما را قادر می‌سازند از ویژگی‌های زبان Kotlin مانند برنامه‌های مشترک، ویژگی‌ها/عملکردهای برنامه افزودنی و غیره استفاده کنید. هر Google Maps SDK دارای یک کتابخانه KTX مربوطه است که در زیر نشان داده شده است:

نمودار KTX پلتفرم نقشه های گوگل

در این کار، از کتابخانه های Maps KTX و Maps Utils KTX برای برنامه خود استفاده می کنید و اجرای کارهای قبلی را اصلاح می کنید تا بتوانید از ویژگی های زبان مخصوص Kotlin در برنامه خود استفاده کنید.

  1. وابستگی های KTX را در فایل build.gradle در سطح برنامه خود قرار دهید

از آنجایی که برنامه از Maps SDK برای Android و Maps SDK for Android Utility Library استفاده می‌کند، باید کتابخانه‌های KTX مربوطه را برای این کتابخانه‌ها اضافه کنید. شما همچنین از یک ویژگی موجود در کتابخانه AndroidX Lifecycle KTX در این کار استفاده خواهید کرد، بنابراین این وابستگی را نیز در فایل build.gradle در سطح برنامه خود قرار دهید.

build.gradle

dependencies {
    // ...

    // Maps SDK for Android KTX Library
    implementation 'com.google.maps.android:maps-ktx:3.0.0'

    // Maps SDK for Android Utility Library KTX Library
    implementation 'com.google.maps.android:maps-utils-ktx:3.0.0'

    // Lifecycle Runtime KTX Library
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
}
  1. از توابع افزونه GoogleMap.addMarker() و GoogleMap.addCircle() استفاده کنید

کتابخانه Maps KTX یک جایگزین API به سبک DSL برای GoogleMap.addMarker(MarkerOptions) و GoogleMap.addCircle(CircleOptions) استفاده شده در مراحل قبلی ارائه می‌کند. برای استفاده از APIهای فوق الذکر، ساخت یک کلاس حاوی گزینه هایی برای نشانگر یا دایره ضروری است، در حالی که با جایگزین های KTX می توانید گزینه های نشانگر یا دایره را در لامبدای که ارائه می کنید، تنظیم کنید.

برای استفاده از این APIها، روش‌های MainActivity.addMarkers(GoogleMap) و MainActivity.addCircle(GoogleMap) را به‌روزرسانی کنید:

MainActivity.addMarkers (GoogleMap)

/**
 * Adds markers to the map. These markers won't be clustered.
 */
private fun addMarkers(googleMap: GoogleMap) {
    places.forEach { place ->
        val marker = googleMap.addMarker {
            title(place.name)
            position(place.latLng)
            icon(bicycleIcon)
        }
        // Set place as the tag on the marker object so it can be referenced within
        // MarkerInfoWindowAdapter
        marker.tag = place
    }
}

MainActivity.addCircle (GoogleMap)

/**
 * Adds a [Circle] around the provided [item]
 */
private fun addCircle(googleMap: GoogleMap, item: Place) {
    circle?.remove()
    circle = googleMap.addCircle {
        center(item.latLng)
        radius(1000.0)
        fillColor(ContextCompat.getColor(this@MainActivity, R.color.colorPrimaryTranslucent))
        strokeColor(ContextCompat.getColor(this@MainActivity, R.color.colorPrimary))
    }
}

بازنویسی روش‌های فوق به این روش بسیار مختصرتر برای خواندن است که با استفاده از تابع Kotlin به معنای واقعی کلمه با گیرنده امکان‌پذیر است.

  1. از توابع تعلیق برنامه افزودنی SupportMapFragment.awaitMap () و GoogleMap.awaitMapLoad() استفاده کنید

کتابخانه Maps KTX همچنین پسوندهای تابع تعلیق را برای استفاده در کوروتین ها فراهم می کند. به طور خاص، گزینه های تعلیق تابع برای SupportMapFragment.getMapAsync(OnMapReadyCallback) و GoogleMap.setOnMapLoadedCallback(OnMapLoadedCallback) وجود دارد. استفاده از این APIهای جایگزین، نیاز به تماس های ارسالی را از بین می برد و در عوض به شما امکان می دهد پاسخ این روش ها را به صورت سریال و همزمان دریافت کنید.

از آنجایی که این روش ها توابع تعلیق هستند، استفاده از آنها باید در یک برنامه کاری انجام شود. کتابخانه Lifecycle Runtime KTX توسعه‌ای را برای ارائه دامنه‌های کوروتین آگاه از چرخه حیات ارائه می‌کند تا برنامه‌های زمانی اجرا شوند و در رویداد چرخه حیات مناسب متوقف شوند.

با ترکیب این مفاهیم، ​​روش MainActivity.onCreate(Bundle) را به روز کنید:

MainActivity.onCreate(Bundle)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val mapFragment =
        supportFragmentManager.findFragmentById(R.id.map_fragment) as SupportMapFragment
    lifecycleScope.launchWhenCreated {
        // Get map
        val googleMap = mapFragment.awaitMap()

        // Wait for map to finish loading
        googleMap.awaitMapLoad()

        // Ensure all places are visible in the map
        val bounds = LatLngBounds.builder()
        places.forEach { bounds.include(it.latLng) }
        googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), 20))

        addClusteredMarkers(googleMap)
    }
}

دامنه coroutine lifecycleScope.launchWhenCreated زمانی بلوک را اجرا می کند که فعالیت حداقل در حالت ایجاد شده باشد. همچنین توجه داشته باشید که فراخوان‌های بازیابی شی GoogleMap و انتظار برای پایان بارگیری نقشه، به ترتیب با SupportMapFragment.awaitMap() و GoogleMap.awaitMapLoad() جایگزین شده‌اند. فاکتورسازی مجدد کد با استفاده از این توابع تعلیق شما را قادر می سازد تا کد مبتنی بر تماس معادل را به صورت متوالی بنویسید.

  1. ادامه دهید و برنامه را با تغییرات بازسازی شده خود دوباره بسازید!

12. تبریک می گویم

تبریک می گویم! شما مطالب زیادی را پوشش دادید و امیدواریم درک بهتری از ویژگی‌های اصلی ارائه شده در Maps SDK برای Android داشته باشید.

بیشتر بدانید

  • مکان‌ها SDK برای Android — مجموعه غنی از داده‌های مکان‌ها را برای کشف مشاغل اطراف خود کاوش کنید.
  • android-maps-ktx — یک کتابخانه منبع باز که به شما امکان می دهد با Maps SDK برای اندروید و Maps SDK برای کتابخانه ابزار اندروید به روشی مناسب برای Kotlin ادغام شوید.
  • android-place-ktx — یک کتابخانه منبع باز که به شما امکان می دهد با Places SDK برای اندروید به روشی مناسب برای Kotlin ادغام شوید.
  • android-samples — کد نمونه در GitHub که تمام ویژگی های پوشش داده شده در این Codelab و موارد دیگر را نشان می دهد.
  • کدهای Kotlin بیشتر برای ساخت برنامه های اندروید با پلتفرم نقشه های گوگل