ميزات Android المتقدمة في Kotlin 04.1: خرائط Google لنظام التشغيل Android

هذا الدرس العملي حول الترميز هو جزء من دورة "تطبيقات متقدّمة متوافقة مع نظام Android باستخدام لغة Kotlin". ستستفيد إلى أقصى حدّ من هذه الدورة التدريبية إذا تابعت دروس الترميز بالتسلسل، ولكن هذا ليس إلزاميًا. يمكنك الاطّلاع على جميع دورات الترميز في الدورة التدريبية على الصفحة المقصودة لدورات الترميز في "تطبيقات متقدمة متوافقة مع نظام Android باستخدام لغة Kotlin".

يتيح لك إنشاء تطبيقات باستخدام "خرائط Google" إضافة ميزات إلى تطبيقك، مثل صور الأقمار الصناعية وعناصر تحكّم قوية في واجهة المستخدم للخرائط وتتبُّع الموقع الجغرافي وعلامات الموقع الجغرافي. يمكنك إضافة قيمة إلى "خرائط Google" العادية من خلال عرض معلومات من مجموعة البيانات الخاصة بك، مثل مواقع مناطق الصيد أو التسلق المعروفة. يمكنك أيضًا إنشاء ألعاب يستكشف فيها اللاعب العالم المادي، مثل البحث عن الكنز أو حتى ألعاب الواقع المعزّز.

في هذا الدرس، ستنشئ تطبيقًا على "خرائط Google" باسم Wander يعرض خرائط مخصّصة ويُظهر الموقع الجغرافي للمستخدم.

المتطلبات الأساسية

المعرفة بما يلي:

  • كيفية إنشاء تطبيق Android أساسي وتشغيله باستخدام "استوديو Android"
  • كيفية إنشاء الموارد وإدارتها، مثل السلاسل
  • كيفية إعادة تصميم الرمز البرمجي وإعادة تسمية المتغيرات باستخدام "استوديو Android"
  • كيفية استخدام خريطة Google كمستخدم
  • كيفية ضبط أذونات وقت التشغيل

أهداف الدورة التعليمية

  • كيفية الحصول على مفتاح واجهة برمجة تطبيقات من "وحدة تحكّم Google API" وتسجيل المفتاح في تطبيقك
  • كيفية دمج "خريطة Google" في تطبيقك
  • كيفية عرض أنواع مختلفة من الخرائط
  • كيفية تصميم خريطة Google
  • كيفية إضافة علامات إلى خريطتك
  • كيفية السماح للمستخدم بوضع علامة على نقطة اهتمام
  • كيفية تفعيل ميزة تتبُّع الموقع الجغرافي
  • كيفية إنشاء تطبيق Wander يتضمّن "خريطة Google"
  • كيفية إنشاء ميزات مخصّصة لتطبيقك، مثل العلامات والأنماط
  • كيفية تفعيل ميزة تتبُّع الموقع الجغرافي في تطبيقك

في هذا الدرس العملي، ستنشئ تطبيق Wander الذي يعرض خريطة Google بتصميم مخصّص. يتيح لك تطبيق Wander إمكانية وضع علامات على المواقع الجغرافية وإضافة تراكبات وعرض موقعك الجغرافي في الوقت الفعلي.

تتطلّب حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" لتطبيقات Android مفتاح واجهة برمجة تطبيقات. للحصول على مفتاح واجهة برمجة التطبيقات، سجِّل مشروعك في صفحة "واجهات برمجة التطبيقات والخدمات". يرتبط مفتاح واجهة برمجة التطبيقات بشهادة رقمية تربط التطبيق بمؤلفه. لمزيد من المعلومات حول استخدام الشهادات الرقمية وتوقيع تطبيقك، يُرجى الاطّلاع على توقيع تطبيقك.

في هذا الدرس التطبيقي، ستستخدم مفتاح واجهة برمجة التطبيقات لشهادة تصحيح الأخطاء. شهادة تصحيح الأخطاء غير آمنة بطبيعتها، كما هو موضّح في توقيع إصدار تصحيح الأخطاء. تتطلّب تطبيقات Android المنشورة التي تستخدم حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" لنظام التشغيل Android مفتاح واجهة برمجة تطبيقات ثانيًا، وهو مفتاح شهادة الإصدار. لمزيد من المعلومات حول الحصول على شهادة إصدار، يُرجى الاطّلاع على الحصول على مفتاح واجهة برمجة التطبيقات.

يتضمّن "استوديو Android" نموذج "نشاط خرائط Google" الذي ينشئ رمز نموذج مفيدًا. يتضمّن رمز النموذج ملف google_maps_api.xml يحتوي على رابط يسهّل الحصول على مفتاح واجهة برمجة التطبيقات.

الخطوة 1: إنشاء مشروع Wander باستخدام نموذج الخرائط

  1. أنشِئ مشروعًا جديدًا في "استوديو Android".
  2. اختَر نموذج نشاط "خرائط Google".

  1. أدخِل اسمًا للمشروع Wander.
  2. اضبط الحد الأدنى لمستوى واجهة برمجة التطبيقات على API 19. تأكَّد من أنّ اللغة هي Kotlin.
  3. انقر على إنهاء.
  4. بعد انتهاء إنشاء التطبيق، ألقِ نظرة على مشروعك وملفات الخرائط التالية التي ينشئها لك "استوديو Android":

google_maps_api.xml: يمكنك استخدام ملف الإعداد هذا لتخزين مفتاح واجهة برمجة التطبيقات. ينشئ النموذج ملفَّين باسم google_maps_api.xml: أحدهما للتصحيح والآخر للإصدار. يقع ملف مفتاح واجهة برمجة التطبيقات لشهادة تصحيح الأخطاء في src/debug/res/values. يقع ملف مفتاح واجهة برمجة التطبيقات لشهادة الإصدار في src/release/res/values. في هذا الدرس العملي، ستستخدم شهادة تصحيح الأخطاء فقط.

activity_maps.xml: يحتوي ملف التصميم هذا على جزء واحد يملأ الشاشة بأكملها. الفئة SupportMapFragment هي فئة فرعية من الفئة Fragment. SupportMapFragment هي أبسط طريقة لوضع خريطة في تطبيق، وهي عبارة عن برنامج تضمين لعرض خريطة من أجل التعامل تلقائيًا مع احتياجات مراحل النشاط الضرورية.

يمكنك تضمين SupportMapFragment في ملف تصميم باستخدام علامة <fragment> في أي ViewGroup، مع إضافة السمة name.

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

MapsActivity.java: ينشئ ملف MapsActivity.kt عنصر SupportMapFragment في طريقة onCreate()، ويستخدم getMapAsync() للفئة من أجل تهيئة نظام الخرائط والعرض تلقائيًا. يجب أن ينفّذ النشاط الذي يحتوي على SupportMapFragment الواجهة OnMapReadyCallback وطريقة onMapReady() الخاصة بهذه الواجهة. يتم استدعاء الطريقة onMapReady() عند تحميل الخريطة.

الخطوة 2: الحصول على مفتاح واجهة برمجة التطبيقات

  1. افتح إصدار تصحيح الأخطاء من ملف google_maps_api.xml.
  2. في الملف، ابحث عن تعليق يتضمّن عنوان URL طويلاً. تتضمّن مَعلمات عنوان URL معلومات محدّدة حول تطبيقك.
  3. انسخ عنوان URL والصقه في المتصفّح.
  4. اتّبِع التعليمات لإنشاء مشروع في صفحة "واجهات برمجة التطبيقات والخدمات". بسبب المَعلمات في عنوان URL المقدَّم، تعرف الصفحة كيفية تفعيل حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" لتطبيقات Android تلقائيًا.
  5. انقر على إنشاء مفتاح واجهة برمجة تطبيقات.
  6. في الصفحة التالية، انتقِل إلى قسم "مفاتيح واجهة برمجة التطبيقات" وانقر على المفتاح الذي أنشأته للتو.
  7. انقر على تقييد المفتاح واختَر حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" لتطبيقات Android لتقييد استخدام المفتاح على تطبيقات Android.
  8. انسخ مفتاح واجهة برمجة التطبيقات الذي تم إنشاؤه. يبدأ بـ "AIza".
  9. في الملف google_maps_api.xml، الصِق المفتاح في السلسلة google_maps_key حيث يظهر YOUR_KEY_HERE.
  10. شغِّل تطبيقك. من المفترض أن تظهر خريطة مضمّنة في نشاطك مع علامة محدّدة في سيدني، أستراليا. (علامة Sydney هي جزء من النموذج ويمكنك تغييرها لاحقًا).

الخطوة 3: إعادة تسمية mMap

يتضمّن MapsActivity سمة خاصة lateinit var باسم mMap، وهي من النوع GoogleMap. للتوافق مع اصطلاحات التسمية في Kotlin، غيِّر اسم mMap إلى map.

  1. في MapsActivity، انقر بزر الماوس الأيمن على mMap وانقر على إعادة تصميم > إعادة تسمية...

  1. غيِّر اسم المتغيّر إلى map.

لاحظ كيف تتغيّر أيضًا جميع المراجع إلى mMap في الدالة onMapReady() إلى map.

تتضمّن "خرائط Google" عدة أنواع من الخرائط: عادية ومختلطة وقمر صناعي وتضاريس و"بلا خريطة" (لعدم عرض أي خريطة على الإطلاق).

الخريطة العادية

خريطة القمر الصناعي

خريطة هجينة

خريطة التضاريس

يقدّم كل نوع من الخرائط أنواعًا مختلفة من المعلومات. على سبيل المثال، عند استخدام الخرائط للتنقّل في السيارة، من المفيد رؤية أسماء الشوارع، لذا يمكنك استخدام الخيار العادي. عند المشي لمسافات طويلة، قد تكون خريطة التضاريس مفيدة لتحديد المسافة المتبقية للوصول إلى القمة.

في هذه المهمة، عليك إجراء ما يلي:

  1. أضِف شريط تطبيق يتضمّن قائمة خيارات تتيح للمستخدم تغيير نوع الخريطة.
  2. حرِّك الموقع الجغرافي الأوّلي للخريطة إلى الموقع الجغرافي لمنزلك.
  3. إضافة دعم للعلامات التي تشير إلى مواقع جغرافية فردية على الخريطة ويمكن أن تتضمّن تصنيفًا

إضافة قائمة لأنواع الخرائط

في هذه الخطوة، ستضيف شريط تطبيقات يتضمّن قائمة خيارات تتيح للمستخدم تغيير نوع الخريطة.

  1. لإنشاء ملف XML جديد للقائمة، انقر بزر الماوس الأيمن على الدليل res واختَر New > Android Resource File.
  2. في مربّع الحوار، اكتب اسمًا للملف map_options.
  3. اختَر القائمة لنوع المورد.
  4. انقر على موافق.
  5. في علامة التبويب الرمز، استبدِل الرمز في الملف الجديد بالرمز التالي لإنشاء خيارات قائمة الخريطة. تم حذف نوع الخريطة "بلا" لأنّ اختيار "بلا" يؤدي إلى عدم ظهور أي خريطة على الإطلاق. تتسبّب هذه الخطوة في حدوث خطأ، ولكنك ستعمل على حلّه في الخطوة التالية.
<?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. انقر على لتغيير نوع الخريطة. لاحظ كيف يتغيّر مظهر الخريطة بين الأوضاع المختلفة.

يتضمّن ردّ الاتصال onMapReady() تلقائيًا رمزًا برمجيًا يضع علامة في سيدني، أستراليا، حيث تم إنشاء "خرائط Google". تعمل دالة الاستدعاء التلقائي أيضًا على تحريك الخريطة للانتقال إلى "سيدني".

في هذه المهمة، ستجعل كاميرا الخريطة تنتقل إلى منزلك، وتكبّر إلى مستوى تحدّده، وتضع علامة هناك.

الخطوة 1: تكبير منزلك وإضافة علامة

  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. حرِّك الكاميرا إلى homeLatLng من خلال استدعاء الدالة moveCamera() على العنصر map وتمرير العنصر CameraUpdate باستخدام CameraUpdateFactory.newLatLngZoom(). مرِّر العنصر 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. شغِّل تطبيقك. من المفترض أن تنتقل الخريطة إلى منزلك، وتُكبَّر إلى المستوى المطلوب، ويتم وضع علامة على منزلك.

الخطوة 2: السماح للمستخدمين بإضافة علامة باستخدام نقرة مع الاستمرار

في هذه الخطوة، ستضيف علامة عندما ينقر المستخدم مع الاستمرار على موقع جغرافي على الخريطة.

  1. أنشئ رمزًا أوليًا للدالة في 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. انقر على العلامة التي ستظهر في وسط الشاشة.

الخطوة 3: إضافة نافذة معلومات للعلامة

في هذه الخطوة، ستضيف InfoWindow يعرض إحداثيات العلامة عند النقر عليها.

  1. في setMapLongClick()setOnMapLongClickListener()، أنشئ val لـ 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.
  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. انقر على محدّد الموقع لإظهار نافذة المعلومات.

الخطوة 4: إضافة أداة معالجة أحداث لنقاط الاهتمام

تظهر تلقائيًا نقاط الاهتمام على الخريطة مع الرموز المقابلة لها. تشمل نقاط الاهتمام المتنزهات والمدارس والمباني الحكومية وغيرها. عند ضبط نوع الخريطة على normal، تظهر أيضًا نقاط الاهتمام الخاصة بالأنشطة التجارية على الخريطة. تمثّل نقاط الاهتمام الخاصة بالأنشطة التجارية الأنشطة التجارية، مثل المتاجر والمطاعم والفنادق.

في هذه الخطوة، يمكنك إضافة GoogleMap.OnPoiClickListener إلى الخريطة. يضع برنامج معالجة النقرات هذا علامة على الخريطة فورًا عندما ينقر المستخدم على نقطة اهتمام. يعرض معالج النقر أيضًا نافذة معلومات تحتوي على اسم نقطة الاهتمام.

  1. أنشئ رمزًا أوليًا للدالة في MapsActivity باسم setPoiClick() يأخذ GoogleMap كمعلَمة.
  2. في طريقة setPoiClick()، اضبط OnPoiClickListener على GoogleMap الذي تم تمريره.
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->

   }
}
  1. في setOnPoiClickListener()، أنشئ val poiMarker للعلامة .
  2. اضبطها على علامة باستخدام map.addMarker() مع MarkerOptions لضبط title على اسم نقطة الاهتمام.
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. شغِّل تطبيقك وابحث عن نقطة اهتمام، مثل حديقة أو مقهى.
  2. انقر على "نقطة الاهتمام" لوضع علامة عليها وعرض اسمها في نافذة معلومات.

يمكنك تخصيص "خرائط Google" بطرق عديدة، ما يمنح خريطتك مظهرًا فريدًا.

يمكنك تخصيص عنصر MapFragment باستخدام سمات XML المتاحة، كما تفعل عند تخصيص أي جزء آخر. ومع ذلك، في هذه الخطوة، يمكنك تخصيص شكل المحتوى في MapFragment باستخدام طرق في العنصر GoogleMap.

لإنشاء نمط مخصّص للخريطة، عليك إنشاء ملف JSON يحدّد كيفية عرض العناصر في الخريطة. لست بحاجة إلى إنشاء ملف JSON هذا يدويًا. توفّر Google أداة تصميم "منصة خرائط Google" التي تنشئ رمز JSON لك بعد تصميم خريطتك بشكل مرئي. في هذه المهمة، ستنسّق الخريطة باستخدام مظهر قديم، ما يعني أنّ الخريطة ستستخدم ألوانًا قديمة وستضيف طرقًا ملوّنة.

الخطوة 1: إنشاء نمط للخريطة

  1. انتقِل إلى https://mapstyle.withgoogle.com/ في المتصفّح.
  2. انقر على إنشاء نمط.
  3. اختَر Retro.

  1. انقر على خيارات إضافية.

  1. في قائمة نوع العنصر، اختَر الطريق > التعبئة.
  2. تغيير لون الطرق إلى أي لون تختاره (مثل الوردي)

  1. انقر على إنهاء.

  1. انسخ رمز JSON من مربّع الحوار الناتج، وإذا أردت، يمكنك تخزينه في ملاحظة نصية عادية لاستخدامه في الخطوة التالية.

الخطوة 2: إضافة النمط إلى الخريطة

  1. في "استوديو Android"، أنشئ دليل موارد في الدليل res وسمِّه raw. يمكنك استخدام موارد دليل raw مثل رمز JSON.
  2. أنشئ ملفًا في res/raw باسم map_style.json.
  3. الصِق رمز JSON المخزَّن في ملف المرجع الجديد.
  4. في MapsActivity، أنشئ متغيّر فئة TAG فوق طريقة onCreate(). يتم استخدام هذا المعرّف لأغراض التسجيل.
private val TAG = MapsActivity::class.java.simpleName
  1. في MapsActivity أيضًا، أنشئ دالة setMapStyle() تأخذ GoogleMap.
  2. في setMapStyle()، أضِف مربّع try{}.
  3. في حزمة try{}، أنشئ val success لنجاح عملية التنسيق. (أضِف كتلة الالتقاط التالية).
  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. أضِف عبارة if ليكون success false. في حال عدم نجاح عملية التنسيق، اطبع سجلّاً يفيد بتعذّر عملية التحليل.
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، وسيظهر التصميم الجديد مع المظهر القديم والطرق باللون الذي اخترته.

الخطوة 3: تصميم العلامة

يمكنك تخصيص خريطتك بشكل أكبر من خلال تصميم علامات الخريطة. في هذه الخطوة، ستغيّر العلامات الحمراء التلقائية إلى علامات أكثر جاذبية.

  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. شغِّل التطبيق. ستظهر العلامات التي تظهر بعد النقر مع الاستمرار باللون الأزرق. يُرجى العِلم أنّ علامات نقاط الاهتمام لا تزال حمراء لأنّك لم تُضِف نمطًا إلى طريقة onPoiClick().

إحدى طرق تخصيص خريطة Google هي الرسم فوقها. تكون هذه الطريقة مفيدة إذا كنت تريد إبراز نوع معيّن من المواقع الجغرافية، مثل أماكن الصيد الشهيرة.

  • الأشكال: يمكنك إضافة خطوط متعددة الأضلاع ومضلّعات ودوائر إلى الخريطة.
  • GroundOverlay العناصر: تراكب الأرضية هو صورة ثابتة على الخريطة. وعلى عكس العلامات، يتم توجيه الصور المتراكبة على الأرض إلى سطح الأرض بدلاً من الشاشة. يؤدي تدوير الخريطة أو إمالتها أو تكبيرها إلى تغيير اتجاه الصورة. تكون الصور المتراكبة على الأرض مفيدة عندما تريد تثبيت صورة واحدة في منطقة واحدة على الخريطة.

الخطوة: إضافة طبقة أرضية

في هذه المهمة، ستضيف صورة طبق الأصل على الأرض على شكل روبوت Android إلى موقع منزلك الجغرافي.

  1. نزِّل صورة Android هذه واحفظها في مجلد res/drawable. (تأكَّد من أنّ اسم الملف هو android.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 للعنصر GroundOverlayOptions من خلال استدعاء الطريقة position()، ثم مرِّر العنصر 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 لعرض صورة Android كتراكب.

يستخدم المستخدمون غالبًا "خرائط Google" لمعرفة موقعهم الجغرافي الحالي. لعرض الموقع الجغرافي للجهاز على الخريطة، يمكنك استخدام طبقة بيانات الموقع الجغرافي.

تضيف طبقة بيانات الموقع الجغرافي موقعي الجغرافي إلى الخريطة. عندما ينقر المستخدم على الزر، تتوسّط الخريطة الموقع الجغرافي للجهاز. يظهر الموقع الجغرافي كنقطة زرقاء إذا كان الجهاز ثابتًا، وكعلامة شيفرون زرقاء إذا كان الجهاز يتحرّك.

في هذه المهمة، عليك تفعيل طبقة بيانات الموقع الجغرافي.

الخطوة: طلب أذونات تحديد الموقع الجغرافي

يتطلّب تفعيل ميزة تتبُّع الموقع الجغرافي في "خرائط Google" سطرًا واحدًا من الرمز. ومع ذلك، يجب التأكّد من أنّ المستخدم قد منح أذونات تحديد الموقع الجغرافي (باستخدام نموذج أذونات التشغيل).

في هذه الخطوة، عليك طلب أذونات تحديد الموقع الجغرافي وتفعيل ميزة تتبُّع الموقع الجغرافي.

  1. في الملف AndroidManifest.xml، تأكَّد من أنّ الإذن FINE_LOCATION متوفّر. أضاف "استوديو Android" هذا الإذن عند اختيار نموذج "خرائط Google".
<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() callback لتفعيل طبقة الموقع الجغرافي.
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. شغِّل تطبيقك. من المفترض أن يظهر مربّع حوار يطلب الوصول إلى الموقع الجغرافي للجهاز. واصِل العملية وامنح الإذن.

تعرض الخريطة الآن الموقع الجغرافي الحالي للجهاز باستخدام نقطة زرقاء. لاحظ أنّه يتضمّن زرًا خاصًا بالموقع الجغرافي. إذا حرّكت الخريطة بعيدًا عن موقعك الجغرافي ونقرت على هذا الزر، ستتم إعادة توسيط الخريطة على الموقع الجغرافي للجهاز.

نزِّل الرمز البرمجي لدرس البرمجة المكتمل.

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


يمكنك بدلاً من ذلك تنزيل المستودع كملف zip وفك ضغطه وفتحه في Android Studio.

تنزيل ملف zip

  • لاستخدام Maps API، تحتاج إلى مفتاح API من وحدة تحكّم Google API.
  • في Android Studio، يؤدي استخدام نموذج "نشاط خرائط Google" إلى إنشاء Activity يتضمّن SupportMapFragment واحدًا في تصميم التطبيق. يضيف النموذج أيضًا ACCESS_FINE_PERMISSION إلى ملف بيان التطبيق، وينفّذ OnMapReadyCallback في نشاطك، ويتجاوز طريقة onMapReady() المطلوبة.

لتغيير نوع خريطة GoogleMap في وقت التشغيل، استخدِم طريقة GoogleMap.setMapType(). يمكن أن تكون "خريطة Google" أحد أنواع الخرائط التالية:

  • عادية: خريطة طرق عادية تعرض هذه الخريطة الطرق وبعض الميزات التي أنشأها الإنسان والميزات الطبيعية المهمة، مثل الأنهار. تظهر أيضًا تصنيفات الطرق والمعالم.
  • هجين: بيانات صور الأقمار الصناعية مع خرائط الطرق تظهر أيضًا تصنيفات الطرق والمعالم.
  • القمر الصناعي: بيانات الصور لا تظهر تصنيفات الطرق والمعالم.
  • التضاريس: بيانات طوبوغرافية تتضمّن الخريطة ألوانًا وخطوطًا كنتورية وتصنيفات وتظليلاً حسب المنظور. تظهر أيضًا بعض الطرق والتصنيفات.
  • بلا: لا يتم عرض مربّعات الخريطة الأساسية.

لمحة عن "خرائط Google":

  • العلامة هي مؤشر لموقع جغرافي محدّد.
  • عند النقر على العلامة، يكون السلوك التلقائي لها هو عرض نافذة معلومات تتضمّن معلومات عن الموقع الجغرافي.
  • تظهر تلقائيًا نقاط الاهتمام على الخريطة الأساسية مع الرموز المقابلة لها. تشمل نقاط الاهتمام المتنزهات والمدارس والمباني الحكومية وغيرها.
  • بالإضافة إلى ذلك، تظهر تلقائيًا نقاط الاهتمام الخاصة بالأنشطة التجارية (المتاجر والمطاعم والفنادق وغيرها) على الخريطة عندما يكون نوع الخريطة normal.
  • يمكنك تسجيل النقرات على "نقاط الاهتمام" باستخدام OnPoiClickListener.
  • يمكنك تغيير المظهر المرئي لجميع عناصر "خريطة Google" تقريبًا باستخدام معالج الأنماط. ينشئ "معالج الأنماط" ملف JSON يمكنك تمريره إلى "خريطة Google" باستخدام الطريقة setMapStyle().
  • يمكنك تخصيص العلامات عن طريق تغيير اللون التلقائي أو استبدال رمز العلامة التلقائي بصورة مخصّصة.

معلومات مهمة أخرى:

  • استخدِم تراكبًا أرضيًا لتثبيت صورة في موقع جغرافي.
  • استخدِم عنصر GroundOverlayOptions لتحديد الصورة وحجمها بالمتر وموضعها. مرِّر هذا العنصر إلى الطريقة GoogleMap.addGroundOverlay() لضبط التراكب على الخريطة.
  • إذا كان تطبيقك لديه إذن ACCESS_FINE_LOCATION، يمكنك تفعيل تتبُّع الموقع الجغرافي من خلال ضبط map.isMyLocationEnabled = true.
  • لا يتضمّن هذا الدرس العملي هذه الميزة، ولكن يمكنك تقديم معلومات إضافية عن موقع جغرافي باستخدام Google Street View، وهي صورة بانورامية قابلة للتصفّح لموقع جغرافي معيّن.

مستندات مطوّري تطبيقات Android:

المستندات المرجعية:

للحصول على روابط تؤدي إلى نماذج أخرى من دروس البرمجة في هذه الدورة التدريبية، يمكنك الاطّلاع على صفحة الوصول إلى نماذج دروس البرمجة في "تطبيقات متقدّمة متوافقة مع نظام Android باستخدام لغة Kotlin".