اندروید پیشرفته در Kotlin 04.1: Android Google Maps

۱. قبل از شروع

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

در این درس، شما یک برنامه Google Maps به نام Wander ایجاد می‌کنید که نقشه‌های سفارشی‌سازی شده و موقعیت مکانی کاربر را نمایش می‌دهد.

پیش‌نیازها

آشنایی با موارد زیر:

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

آنچه یاد خواهید گرفت

  • نحوه دریافت کلید API از کنسول API گوگل و ثبت کلید در برنامه شما
  • نحوه ادغام نقشه گوگل در برنامه شما
  • نحوه نمایش انواع مختلف نقشه
  • نحوه استایل دادن به نقشه گوگل
  • نحوه اضافه کردن نشانگر به نقشه شما
  • چگونه به کاربر امکان دهیم که روی یک نقطه مورد نظر (POI) علامت‌گذاری کند؟
  • نحوه فعال کردن ردیابی موقعیت مکانی
  • نحوه ایجاد برنامه The Wander که دارای نقشه گوگل جاسازی شده است
  • نحوه ایجاد ویژگی‌های سفارشی برای برنامه شما، مانند نشانگرها و استایل‌بندی
  • نحوه فعال کردن ردیابی موقعیت مکانی در برنامه شما

۲. مرور کلی برنامه

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

5b12eda7f467bc2f.png

۳. وظیفه: راه‌اندازی پروژه و دریافت کلید API

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

در این آزمایشگاه کد، شما از کلید API برای گواهی اشکال‌زدایی استفاده می‌کنید. گواهی اشکال‌زدایی، همانطور که در بخش امضای نسخه اشکال‌زدایی توضیح داده شده است، از نظر طراحی ناامن است. برنامه‌های اندروید منتشر شده که از Maps SDK برای اندروید استفاده می‌کنند، به یک کلید API دوم نیاز دارند: کلید گواهی انتشار. برای اطلاعات بیشتر در مورد دریافت گواهی انتشار، به دریافت کلید API مراجعه کنید.

اندروید استودیو شامل یک الگوی فعالیت نقشه‌های گوگل است که کد الگوی مفیدی تولید می‌کند. کد الگو شامل یک فایل google_maps_api.xml است که حاوی لینکی است که دریافت کلید API را ساده می‌کند.

مرحله ۱: ایجاد پروژه Wander با استفاده از الگوی نقشه‌ها

  1. یک پروژه جدید اندروید استودیو ایجاد کنید.
  2. الگوی فعالیت نقشه‌های گوگل را انتخاب کنید.

d6b874bb19ea68cd.png

  1. نام پروژه را Wander .
  2. حداقل سطح API را روی API 19 تنظیم کنید. مطمئن شوید که زبان Kotlin است.
  3. روی پایان کلیک کنید.
  4. پس از اتمام ساخت برنامه، به پروژه خود و فایل‌های مربوط به نقشه‌های زیر که اندروید استودیو برای شما ایجاد می‌کند، نگاهی بیندازید:

google_maps_api.xml — شما از این فایل پیکربندی برای نگهداری کلید API خود استفاده می‌کنید. این الگو دو فایل google_maps_api.xml تولید می‌کند: یکی برای اشکال‌زدایی و دیگری برای انتشار. فایل مربوط به کلید API برای گواهی اشکال‌زدایی در src/debug/res/values ​​قرار دارد. فایل مربوط به کلید API برای گواهی انتشار در src/release/res/values ​​قرار دارد. در این codelab، شما فقط از گواهی اشکال‌زدایی استفاده می‌کنید.

activity_maps.xml — این فایل طرح‌بندی شامل یک قطعه کد واحد است که کل صفحه را پر می‌کند. کلاس SupportMapFragment یک زیرکلاس از کلاس Fragment است. یک SupportMapFragment ساده‌ترین راه برای قرار دادن یک نقشه در یک برنامه است. این یک پوشش در اطراف نمای یک نقشه است تا به طور خودکار نیازهای چرخه عمر لازم را مدیریت کند.

شما می‌توانید SupportMapFragment با استفاده از یک تگ <fragment> در هر ViewGroup و با یک ویژگی name اضافی، در یک فایل layout قرار دهید.

android:name="com.google.android.gms.maps.SupportMapFragment"

MapsActivity.java — فایل MapsActivity.kt ، SupportMapFragment را در متد onCreate() نمونه‌سازی می‌کند و از کلاس getMapAsync () برای مقداردهی اولیه خودکار سیستم نقشه‌ها و نما استفاده می‌کند. اکتیویتی که شامل SupportMapFragment است، باید رابط OnMapReadyCallback و متد onMapReady() آن رابط را پیاده‌سازی کند. متد onMapReady() هنگام بارگذاری نقشه فراخوانی می‌شود.

مرحله ۲: دریافت کلید API

  1. نسخه اشکال‌زدایی فایل google_maps_api.xml را باز کنید.
  2. در فایل، به دنبال کامنتی با آدرس اینترنتی (URL) طولانی باشید. پارامترهای این آدرس اینترنتی شامل اطلاعات خاصی در مورد برنامه شما هستند.
  3. آدرس اینترنتی (URL) را کپی کرده و در مرورگر جایگذاری کنید.
  4. برای ایجاد یک پروژه در صفحه APIها و خدمات ، دستورالعمل‌ها را دنبال کنید. به دلیل پارامترهای موجود در URL ارائه شده، صفحه می‌داند که به طور خودکار Maps SDK را برای اندروید فعال کند.
  5. روی ایجاد کلید API کلیک کنید.
  6. در صفحه بعد، به بخش کلیدهای API بروید و روی کلیدی که ایجاد کرده‌اید کلیک کنید.
  7. روی Restrict Key کلیک کنید و Maps SDK for Android را انتخاب کنید تا استفاده از کلید به برنامه‌های اندروید محدود شود.
  8. کلید API تولید شده را کپی کنید. با " AIza" شروع می‌شود.
  9. در فایل google_maps_api.xml ، کلید را در رشته google_maps_key جایی که YOUR_KEY_HERE نوشته شده است، جایگذاری کنید.
  10. برنامه خود را اجرا کنید. باید یک نقشه جاسازی شده در activity خود با نشانگری که در سیدنی، استرالیا تنظیم شده است، ببینید. (نشانگر سیدنی بخشی از الگو است و بعداً آن را تغییر می‌دهید.)

34dc9dd877c90996.png

مرحله ۳: تغییر نام mMap

MapsActivity یک var lateinit خصوصی به نام mMap دارد که از نوع GoogleMap است. برای پیروی از قراردادهای نامگذاری Kotlin، نام mMap را به map تغییر دهید.

  1. در MapsActivity ، روی mMap کلیک راست کرده و Refactor > Rename... را انتخاب کنید.

e713ccb3384450c6.png

  1. نام متغیر را به map تغییر دهید.

توجه کنید که چگونه تمام ارجاعات به mMap در تابع onMapReady() نیز به map تغییر می‌کنند.

۴. وظیفه: اضافه کردن انواع نقشه

نقشه‌های گوگل شامل چندین نوع نقشه هستند: معمولی، ترکیبی، ماهواره‌ای، زمینی و «هیچ» (یعنی اصلاً نقشه‌ای وجود ندارد).

نقشه عادی

نقشه ماهواره‌ای

نقشه ترکیبی

نقشه زمین

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

در این وظیفه شما:

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

اضافه کردن منو برای انواع نقشه

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

  1. برای ایجاد یک فایل XML منوی جدید، روی دایرکتوری res خود راست کلیک کرده و New > Android Resource File را انتخاب کنید.
  2. در کادر محاوره‌ای، نام فایل را map_options بگذارید.
  3. برای نوع منبع، منو را انتخاب کنید.
  4. روی تأیید کلیک کنید.
  5. در تب Code ، کد موجود در فایل جدید را با کد زیر جایگزین کنید تا گزینه‌های منوی نقشه ایجاد شود. نوع نقشه "none" حذف شده است زیرا "none" منجر به عدم وجود هیچ نقشه‌ای می‌شود. این مرحله باعث ایجاد خطا می‌شود، اما شما آن را در مرحله بعدی برطرف می‌کنید.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
       android:id="@+id/normal_map"
       android:title="@string/normal_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/hybrid_map"
       android:title="@string/hybrid_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/satellite_map"
       android:title="@string/satellite_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/terrain_map"
       android:title="@string/terrain_map"
       app:showAsAction="never" />
</menu>
  1. در strings.xml ، منابعی را برای ویژگی‌های title اضافه کنید تا خطاها برطرف شوند.
<resources>
   ...
   <string name="normal_map">Normal Map</string>
   <string name="hybrid_map">Hybrid Map</string>
   <string name="satellite_map">Satellite Map</string>
   <string name="terrain_map">Terrain Map</string>
   <string name="lat_long_snippet">Lat: %1$.5f, Long: %2$.5f</string>
   <string name="dropped_pin">Dropped Pin</string>
   <string name="poi">poi</string>
</resources>
  1. در MapsActivity ، متد onCreateOptionsMenu() را بازنویسی کنید و منو را از فایل منبع map_options ایجاد کنید.
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
   val inflater = menuInflater
   inflater.inflate(R.menu.map_options, menu)
   return true
}
  1. در MapsActivity.kt ، متد onOptionsItemSelected() را بازنویسی کنید. نوع نقشه را با استفاده از ثابت‌های نوع نقشه تغییر دهید تا انتخاب کاربر را منعکس کند.
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
   // Change the map type based on the user's selection.
   R.id.normal_map -> {
       map.mapType = GoogleMap.MAP_TYPE_NORMAL
       true
   }
   R.id.hybrid_map -> {
       map.mapType = GoogleMap.MAP_TYPE_HYBRID
       true
   }
   R.id.satellite_map -> {
       map.mapType = GoogleMap.MAP_TYPE_SATELLITE
       true
   }
   R.id.terrain_map -> {
       map.mapType = GoogleMap.MAP_TYPE_TERRAIN
       true
   }
   else -> super.onOptionsItemSelected(item)
}
  1. برنامه را اجرا کنید.
  2. کلیک 428da163b831115b.png برای تغییر نوع نقشه. توجه کنید که ظاهر نقشه چگونه بین حالت‌های مختلف تغییر می‌کند.

6fa42970d87f5dc7.png

۵. وظیفه: اضافه کردن نشانگرها

به طور پیش‌فرض، تابع فراخوانی onMapReady() شامل کدی است که یک نشانگر را در سیدنی، استرالیا، جایی که نقشه‌های گوگل ایجاد شده‌اند، قرار می‌دهد. این تابع فراخوانی پیش‌فرض همچنین نقشه را برای حرکت به سمت سیدنی متحرک می‌کند.

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

مرحله ۱: روی خانه خود زوم کنید و یک نشانگر اضافه کنید

  1. در فایل MapsActivity.kt ، متد onMapReady() را پیدا کنید. کدی که نشانگر را در سیدنی قرار می‌دهد و دوربین را حرکت می‌دهد را از آن حذف کنید. اکنون متد شما باید به این شکل باشد.
override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

}
  1. با دنبال کردن این دستورالعمل‌ها، طول و عرض جغرافیایی خانه خود را پیدا کنید.
  2. یک مقدار برای عرض جغرافیایی و یک مقدار برای طول جغرافیایی ایجاد کنید و مقادیر اعشاری آنها را وارد کنید.
val latitude = 37.422160
val longitude = -122.084270
  1. یک شیء LatLng جدید به نام homeLatLng ایجاد کنید. در شیء homeLatLng ، مقادیری را که ایجاد کرده‌اید، وارد کنید.
val homeLatLng = LatLng(latitude, longitude)
  1. برای میزان بزرگنمایی مورد نظر خود روی نقشه، یک val ایجاد کنید. از سطح بزرگنمایی 15f استفاده کنید.
val zoomLevel = 15f

سطح بزرگنمایی، میزان بزرگنمایی شما روی نقشه را کنترل می‌کند. لیست زیر به شما نشان می‌دهد که هر سطح بزرگنمایی چه سطحی از جزئیات را نشان می‌دهد:

  • 1 : جهان
  • 5 : خشکی/قاره
  • 10 : شهر
  • 15 : خیابان‌ها
  • 20 : ساختمان‌ها
  1. با فراخوانی تابع moveCamera() روی شیء map ، دوربین را به homeLatLng منتقل کنید و با استفاده از CameraUpdateFactory.newLatLngZoom() یک شیء CameraUpdate به آن ارسال کنید. شیء homeLatLng و zoomLevel نیز ارسال کنید.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
  1. یک نشانگر به نقشه در homeLatLng اضافه کنید.
map.addMarker(MarkerOptions().position(homeLatLng))

متد نهایی شما باید به این شکل باشد:

override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

   //These coordinates represent the latitude and longitude of the Googleplex.
   val latitude = 37.422160
   val longitude = -122.084270
   val zoomLevel = 15f

   val homeLatLng = LatLng(latitude, longitude)
   map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
   map.addMarker(MarkerOptions().position(homeLatLng))
}
  1. برنامه خود را اجرا کنید. نقشه باید به خانه شما حرکت کند، تا سطح مورد نظر بزرگنمایی کند و یک نشانگر روی خانه شما قرار دهد.

fc939024778ee76.png

مرحله ۲: به کاربران اجازه دهید با استفاده از یک کلیک طولانی، یک نشانگر اضافه کنند

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

  1. یک متد stub در MapsActivity به نام setMapLongClick() ایجاد کنید که یک GoogleMap به عنوان آرگومان دریافت کند.
  2. یک شنونده‌ی setOnMapLongClickListener به شیء نقشه اضافه کنید.
private fun setMapLongClick(map:GoogleMap) {
   map.setOnMapLongClickListener { }
}
  1. در setOnMapLongClickListener() ، متد addMarker() فراخوانی کنید. یک شیء MarkerOptions جدید با موقعیت تنظیم‌شده روی LatLng ارسالی، به آن ارسال کنید.
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. در پایان متد onMapReady() ، تابع setMapLongClick() را به همراه map فراخوانی کنید.
override fun onMapReady(googleMap: GoogleMap) {
   ...
  
   setMapLongClick(map)
}
  1. برنامه خود را اجرا کنید.
  2. برای قرار دادن نشانگر در یک مکان، نقشه را لمس کرده و نگه دارید.
  3. روی نشانگر ضربه بزنید، که آن را در مرکز صفحه قرار می‌دهد.

4ff8d1c1db3bca9e.png

مرحله ۳: یک پنجره اطلاعات برای نشانگر اضافه کنید

در این مرحله، یک InfoWindow اضافه می‌کنید که مختصات نشانگر را هنگام ضربه زدن به نشانگر نمایش می‌دهد.

  1. در setMapLongClick()setOnMapLongClickListener() ، یک val برای snippet ایجاد کنید. snippet متن اضافی است که بعد از عنوان نمایش داده می‌شود. snippet شما طول و عرض جغرافیایی یک نشانگر را نمایش می‌دهد.
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       // A snippet is additional text that's displayed after the title.
       val snippet = String.format(
           Locale.getDefault(),
           "Lat: %1$.5f, Long: %2$.5f",
           latLng.latitude,
           latLng.longitude
       )
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. در addMarker() ، title نشانگر را با استفاده از منبع رشته‌ای R.string. به dropped_pin Pin تنظیم کنید.
  2. snippet نشانگر را روی snippet تنظیم کنید.

تابع تکمیل‌شده به این شکل است:

private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       // A Snippet is Additional text that's displayed below the title.
       val snippet = String.format(
           Locale.getDefault(),
           "Lat: %1$.5f, Long: %2$.5f",
           latLng.latitude,
           latLng.longitude
       )
       map.addMarker(
           MarkerOptions()
               .position(latLng)
               .title(getString(R.string.dropped_pin))
               .snippet(snippet)
              
       )
   }
}
  1. برنامه خود را اجرا کنید.
  2. برای نمایش نشانگر مکان، نقشه را لمس کرده و نگه دارید.
  3. برای نمایش پنجره اطلاعات، روی نشانگر ضربه بزنید.

63f210e6e47dfa29.png

مرحله ۴: اضافه کردن شنونده POI

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

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

  1. یک متد stub در MapsActivity به نام setPoiClick() ایجاد کنید که یک GoogleMap به عنوان آرگومان دریافت کند.
  2. در متد setPoiClick() ، یک OnPoiClickListener روی GoogleMap ارسالی تنظیم کنید.
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->

   }
}
  1. در تابع setOnPoiClickListener() ، یک val poiMarker برای نشانگر ایجاد کنید.
  2. با استفاده از map.addMarker() و با تنظیم title به نام POI توسط MarkerOptions ، آن را روی یک نشانگر تنظیم کنید.
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
   }
}
  1. در تابع setOnPoiClickListener() ، تابع showInfoWindow() را روی poiMarker فراخوانی کنید تا پنجره اطلاعات بلافاصله نمایش داده شود.
poiMarker.showInfoWindow()

کد نهایی شما برای تابع setPoiClick() باید به این شکل باشد.

private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
       poiMarker.showInfoWindow()
   }
}
  1. در انتهای onMapReady() ، تابع setPoiClick() را فراخوانی کرده و map را به آن ارسال کنید.
override fun onMapReady(googleMap: GoogleMap) {
   ...

   setPoiClick(map)
}
  1. برنامه خود را اجرا کنید و یک POI (نقطه مورد نظر) مانند پارک یا کافی‌شاپ پیدا کنید.
  2. روی نقطه مورد نظر (POI) ضربه بزنید تا یک نشانگر روی آن قرار گیرد و نام آن در یک پنجره اطلاعات نمایش داده شود.

f4b0972c75d5fa5f.png

۶. وظیفه: نقشه خود را سبک‌بندی کنید

شما می‌توانید نقشه‌های گوگل را از بسیاری جهات سفارشی کنید و به نقشه خود ظاهر و حس منحصر به فردی ببخشید.

شما می‌توانید یک شیء MapFragment را با استفاده از ویژگی‌های XML موجود، همانطور که هر قطعه کد دیگری را سفارشی می‌کنید، سفارشی کنید. با این حال، در این مرحله، ظاهر و حس محتوای MapFragment را با استفاده از متدهای شیء GoogleMap سفارشی می‌کنید.

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

مرحله ۱: یک سبک برای نقشه خود ایجاد کنید

  1. در مرورگر خود به آدرس https://mapstyle.withgoogle.com/ بروید.
  2. ایجاد یک سبک را انتخاب کنید.
  3. رترو را انتخاب کنید.

208b3d3aeab0d9b6.png

  1. روی گزینه‌های بیشتر کلیک کنید.

4a35faaf9535ee82.png

  1. جاده > پر کردن را انتخاب کنید.
  2. رنگ جاده‌ها را به هر رنگی که انتخاب می‌کنید (مثلاً صورتی) تغییر دهید.

92c3293749293a4c.png

  1. روی پایان کلیک کنید.

f1bfe8585eb69480.png

  1. کد JSON را از کادر محاوره‌ای حاصل کپی کنید و در صورت تمایل، آن را در یک یادداشت متنی ساده برای استفاده در مرحله بعدی ذخیره کنید.

3c32168b299d6420.png

مرحله ۲: سبک را به نقشه خود اضافه کنید

  1. در اندروید استودیو، در پوشه res ، یک پوشه منابع ایجاد کنید و نام آن را raw بگذارید. شما از منابع پوشه raw مانند کد JSON استفاده می‌کنید.
  2. یک فایل در res/raw با نام map_style.json ایجاد کنید.
  3. کد JSON ذخیره شده خود را در فایل منبع جدید جایگذاری کنید.
  4. در MapsActivity ، یک متغیر کلاس TAG بالای متد onCreate() ایجاد کنید. این برای اهداف ثبت وقایع (logging) استفاده می‌شود.
private val TAG = MapsActivity::class.java.simpleName
  1. همچنین در MapsActivity ، یک تابع setMapStyle() ایجاد کنید که یک GoogleMap را دریافت کند.
  2. در setMapStyle() ، یک بلوک try{} اضافه کنید.
  3. در بلوک try{} ، یک val success برای موفقیت استایل‌بندی ایجاد کنید. (شما بلوک catch زیر را اضافه می‌کنید.)
  4. در بلوک try{} ، سبک JSON را روی نقشه تنظیم کنید، تابع setMapStyle() را روی شیء GoogleMap فراخوانی کنید. یک شیء MapStyleOptions را به آن ارسال کنید که فایل JSON را بارگذاری می‌کند.
  5. نتیجه را به success اختصاص دهید. متد setMapStyle() یک مقدار بولی برمی‌گرداند که نشان دهنده وضعیت موفقیت‌آمیز تجزیه فایل استایل‌بندی و تنظیم استایل است.
private fun setMapStyle(map: GoogleMap) {
   try {
       // Customize the styling of the base map using a JSON object defined
       // in a raw resource file.
       val success = map.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
               this,
               R.raw.map_style
           )
       )
   }
}
  1. اگر تابع success در حالت false قرار داشت، یک دستور if اضافه کنید. اگر استایل‌بندی ناموفق بود، گزارشی مبنی بر ناموفق بودن تجزیه چاپ کند.
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   }
}
  1. یک بلوک catch{} برای مدیریت وضعیت فقدان فایل استایل اضافه کنید. در بلوک catch ، اگر فایل قابل بارگذاری نباشد، یک Resources.NotFoundException ایجاد کنید.
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}

متد نهایی باید شبیه قطعه کد زیر باشد:

private fun setMapStyle(map: GoogleMap) {
   try {
       // Customize the styling of the base map using a JSON object defined
       // in a raw resource file.
       val success = map.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
               this,
               R.raw.map_style
           )
       )

       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}
  1. در نهایت، متد setMapStyle() را در متد onMapReady() که شیء GoogleMap خود را به آن ارسال می‌کنید، فراخوانی کنید.
override fun onMapReady(googleMap: GoogleMap) {
   ...
   setMapStyle(map)
}
  1. برنامه خود را اجرا کنید.
  2. نقشه را روی حالت normal تنظیم کنید و ظاهر جدید باید با تم رترو و جاده‌هایی با رنگ انتخابی شما قابل مشاهده باشد.

b59d6cb81f02a14f.png

مرحله ۳: به ماژیک خود استایل بدهید

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

  1. در متد onMapLongClick() ، خط کد زیر را به MarkerOptions() از سازنده اضافه کنید تا از نشانگر پیش‌فرض استفاده شود، اما رنگ آن به آبی تغییر کند.
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))

حالا onMapLongClickListener() به این شکل در می‌آید:

map.setOnMapLongClickListener { latLng ->
   // A snippet is additional text that's displayed after the title.
   val snippet = String.format(
       Locale.getDefault(),
       "Lat: %1$.5f, Long: %2$.5f",
       latLng.latitude,
       latLng.longitude
   )
   map.addMarker(
       MarkerOptions()
           .position(latLng)
           .title(getString(R.string.dropped_pin))
           .snippet(snippet)
         .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
   )
}
  1. برنامه را اجرا کنید. نشانگرهایی که پس از کلیک طولانی شما ظاهر می‌شوند، اکنون به رنگ آبی سایه‌دار هستند. توجه داشته باشید که نشانگرهای POI هنوز قرمز هستند زیرا شما به متد onPoiClick() استایل اضافه نکرده‌اید.

b9916bca3c367e3.png

۷. وظیفه: اضافه کردن یک پوشش

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

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

مرحله: یک پوشش زمینی اضافه کنید

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

  1. این تصویر اندروید را دانلود کنید و آن را در پوشه res/drawable خود ذخیره کنید. (مطمئن شوید که نام فایل android.png است.)

61fabd56a0841b44.png

  1. در onMapReady() ، پس از فراخوانی برای انتقال دوربین به موقعیت خانه، یک شیء GroundOverlayOptions ایجاد کنید.
  2. شیء را به متغیری به نام androidOverlay اختصاص دهید.
val androidOverlay = GroundOverlayOptions()
  1. از متد BitmapDescriptorFactory.fromResource() برای ایجاد یک شیء BitmapDescriptor از منبع تصویر دانلود شده استفاده کنید.
  2. شیء BitmapDescriptor حاصل را به متد image() از شیء GroundOverlayOptions ارسال کنید.
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
  1. یک float overlaySize برای عرض پوشش مورد نظر بر حسب متر ایجاد کنید. برای این مثال، عرض 100f خوب جواب می‌دهد.

با فراخوانی متد position() ‎، ویژگی position (position) را برای شیء GroundOverlayOptions تنظیم کنید و شیء homeLatLng و overlaySize به آن ارسال کنید.

val overlaySize = 100f
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
   .position(homeLatLng, overlaySize)
  1. تابع addGroundOverlay() را روی شیء GoogleMap فراخوانی کنید و شیء GroundOverlayOptions خود را به آن ارسال کنید.
map.addGroundOverlay(androidOverlay)
  1. برنامه را اجرا کنید.
  2. برای دیدن تصویر اندروید به صورت یک لایه رویی، مقدار zoomLevel را به 18f تغییر دهید.

b1b25b0acd6a9807.png

۸. وظیفه: فعال کردن ردیابی موقعیت مکانی

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

لایه داده‌های مکانی، آیکون «موقعیت مکانی من» را به نقشه اضافه می‌کند.

f317f84dcb3ac3a1.png

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

در این کار، لایه داده‌های مکانی را فعال می‌کنید.

مرحله: درخواست مجوزهای مکان

فعال کردن ردیابی موقعیت مکانی در گوگل مپ به یک خط کد نیاز دارد. با این حال، باید مطمئن شوید که کاربر مجوزهای موقعیت مکانی را اعطا کرده است (با استفاده از مدل runtime-permission).

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

  1. در فایل AndroidManifest.xml ، تأیید کنید که مجوز FINE_LOCATION از قبل وجود دارد. اندروید استودیو این مجوز را هنگام انتخاب الگوی Google Maps وارد کرده است.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  1. در MapsActivity ، یک متغیر کلاس REQUEST_LOCATION_PERMISSION ایجاد کنید.
private val REQUEST_LOCATION_PERMISSION = 1
  1. برای بررسی اینکه آیا مجوزها اعطا شده‌اند یا خیر، متدی در MapsActivity به نام isPermissionGranted() ایجاد کنید. در این متد، بررسی کنید که آیا کاربر مجوز را اعطا کرده است یا خیر.
private fun isPermissionGranted() : Boolean {
  return ContextCompat.checkSelfPermission(
       this,
      Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
  1. برای فعال کردن ردیابی موقعیت مکانی در برنامه خود، متدی در MapsActivity به نام enableMyLocation() ایجاد کنید که هیچ آرگومانی نمی‌گیرد و چیزی برنمی‌گرداند. درون آن، مجوز ACCESS_FINE_LOCATION را بررسی کنید. اگر مجوز اعطا شد، لایه موقعیت مکانی را فعال کنید. در غیر این صورت، مجوز را درخواست کنید.
private fun enableMyLocation() {
   if (isPermissionGranted()) {
       map.isMyLocationEnabled = true 
   }
   else {
       ActivityCompat.requestPermissions(
           this,
           arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
           REQUEST_LOCATION_PERMISSION
       )
   }
}
  1. برای فعال کردن لایه موقعیت مکانی، تابع enableMyLocation() را از تابع onMapReady() فراخوانی کنید.
override fun onMapReady(googleMap: GoogleMap) {
   ...
   enableMyLocation()
}
  1. متد onRequestPermissionsResult() را بازنویسی کنید. بررسی کنید که آیا requestCode برابر با REQUEST_LOCATION_PERMISSION است یا خیر. اگر چنین است، به این معنی است که مجوز اعطا شده است. اگر مجوز اعطا شده است، همچنین بررسی کنید که آیا آرایه grantResults شامل PackageManager.PERMISSION_GRANTED در اولین جایگاه خود است یا خیر. اگر این مقدار درست بود، enableMyLocation() را فراخوانی کنید.
override fun onRequestPermissionsResult(
   requestCode: Int,
   permissions: Array<String>,
   grantResults: IntArray) {
   if (requestCode == REQUEST_LOCATION_PERMISSION) {
       if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
           enableMyLocation()
       }
   }
}
  1. برنامه خود را اجرا کنید. باید یک پنجره محاوره‌ای وجود داشته باشد که درخواست دسترسی به موقعیت مکانی دستگاه را می‌دهد. ادامه دهید و اجازه دسترسی را بدهید.

da7e23e00ec762c1.png

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

5b12eda7f467bc2f.png

۹. کد راه‌حل

کد مربوط به codelab نهایی را دانلود کنید.

$  git clone https://github.com/googlecodelabs/android-kotlin-geo-maps

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

۱۰. خلاصه

تبریک! شما یک نقشه گوگل را به یک برنامه اندروید کاتلین اضافه کردید و آن را استایل‌بندی کردید.

۱۱. بیشتر بدانید

مستندات توسعه‌دهندگان اندروید:

مستندات مرجع:

۱۲. آزمایشگاه کد بعدی

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