Android üzerinde Google Maps API Kullanımı
Herkese selamlar. Volt Lines olarak mobil uygulamalarımızın ana kısımlarından biri de map kullanımı ve map ile birlikte sunduğumuz özelliklerdir. Hem sürücü hem de yolcu uygulamalarımızda bazı spesifik gösterimlerimiz vardır. Bunlara rotaların polyline’ları ve point’lerin marker’larını örnek verebiliriz. Bizler bu özellikleri kullanırken aslında sahadan(sürücülerimizden) ve kullanıcılarımızdan aldığımız geri bildirimler ile birlikte en optimize şekilde kullanmaya çalışmaktayız. Eğer sizler de kendi uygulamalarınız üzerinde, bizlerin kullandığı özelliklerin benzerlerini kullanmak istiyorsanız basit bir şekilde bunların implementasyonlarına birlikte göz atalım.
Her şeyden önce Android Projeniz üzerinde Google Map API’sini kullanabilmek için API key’e ihtiyacınız vardır. Buradaki Google dokümantasyonu takip ederek kendi Gmail adresiniz ile bir API key almanız gerekmektedir. Daha sonrasında API key’inizi google_maps_api.xml ve Manifest dosyasına eklemeniz gereklidir.
Google dokümantasyonlarını takip edip API key’ini projemize eklediğimize göre artık projemizde map ve map’e özgü feature’ları kullanabiliriz.
Projenize Android Studio üzerinden default bir Map Activity yaratmak isterseniz karşınıza aslında comment line’lar ile birlikte örnek bir map implementasyonu gelecektir. İlk olarak bu örnek üzerindeki yapıları açıklamak gerekirse;
SupportMapFragment: En basit haliyle Fragment’dan extend edilmiş bir map fragment’dır diyebiliriz. Kendisi bir fragment olduğu için layout içinde fragment olarak çağırabilir ve bu sayede view üzerinde map’i yansıtabiliriz.
getMapAsync: Bu function sayesinde onMapReadyCallback yapısını içinde tanımladığımız takdirde map’i initialize edebiliriz.
onMapReady: Map initialize olduktan sonra bize pasladığı GoogleMap tipindeki bir value ile birlikte code-base üzerinde map view işlemlerini yapabiliriz.
addMarker: Bu kısmı ileride biraz daha detaylandıracağız fakat kısaca map üzerinde marker gösterimlerini gerçekleştirmemizi sağlar. Varsayılan bir marker görünümü verebileceği gibi bizlerin de Volt Lines üzerinde yaptığımız gibi kendi iş gereksinimlerinize uygun bir şekilde de kendi custom yapılarınızı ekleyebilirsiniz.
moveCamera: Map üzerinde görünümün focuslanması kontrol ettiğiniz yapıdır. CameraUpdateFactory class’ının altında ihtiyaçlarınıza göre farklı kullanım senaryoları yaratacağınız function’lar da bulunmaktadır.
Custom MapFragment Kullanımı
Custom bir map fragment yapısı oluşturmak aslında tamamiyle developer’ın ihtiyaçlarına bağlıdır. Bizler, Volt Lines’ın uygulamalarında da sadece tek bir yerde map fragment’ı kullanmamaktayız. Aynı zamanda, kullanacağımız bu map fragment’ların belli ortak kuralları bulunmaktadır. Bu sebeple her seferinde layout üzerinde SupportMapFragment kullanıp daha sonrasında her sayfa için özelleştirme yapmak yerine custom bir map fragment oluşturup bunun üzerinde ortak kuralları belirleyip kullanmaktayız. Aynı zamanda bu yapının bizlere sunduğu esneklik sayesinde her sayfanın kendine has isteklerini de ayriyeten o bölüm içinde tanımlayabilmekteyiz.
Bu sefer direkt olarak Activity veya Fragment için SupportMapFragment kullanmak yerine bu class’ı extend eden kendi custom map fragment’ımızı yarattık. İçine, her CustomMapFragment’ı kullanacak yapıların otomatik olarak uygulaması için, bazı değerler set ettik. Bu sayede bu class’ı kullanan her yapı otomatik olarak bu değerler ile haritayı initalize edecektir.
Kullanacağımız function’ları interface üzerinden yaratıp, class’ımıza bu interface’i implement ettik. Bunu yapmak zorunda değilsiniz lakin, code management (kod yönetimi) ve clean code (yalın kod) vb. şeyler için interface kullanmanızı tavsiye ederim.
Oluşturduğumuz CustomMapFragment’ı MapsActivity içinde oluşturduk. supportMapManager yapısı ile layout içindeki fragment component’imizi class içinde tanımladık ve bu tanımlamayı yaparken de oluşturduğumuz CustomMapFragment’a cast etmiş bulunduk. mapReady function’ı ile de googleMap değerini map fragment’ımıza set ettik. Sonrasında Ortak yapımızda olan bazı kuralları değiştirdik. Zoom level’ı 12F, trafik bilgisini de false değeri ile map işlemleri için tanımladık. Bu sayede ortak değerler haricinde çağırdığımız class içinde map view’ı özelleştirebilmiş olduk.
Activity’imizin layout’u içinde bu sefer SupportMapFragment’ı kullanmak yerine CustomMapFragment’ı kullandık.
Bugüne kadar map fragment’ımızı hep activity içlerinde çağırdık. Daha önceden de bahsettiğimiz gibi CustomMapFragment’ımızın en iyi özelliği birden fazla yerde map kullanmak istersek ortak değerler set edebilmemizi sağlamasıydı. Bu sebeple aynı proje için hem activity üzerinden hem de fragment üzerinden bu oluşturduğumuz map fragment’ı çağırabiliriz.
ParentFragment adında bir fragment oluşturduk. Sonrasında ise fragment manager yardımı ile layout içindeki fragment’ımızı class’ımızda tanımlıyoruz. Fakat bu sefer bir fragment içinde fragment çağırdığımız için childFragmentManager kullanıyoruz. Sonrasında ise CustomMapFragment’ın mapReady function’nın içine getMapAsync’den aldığımız değeri gönderiyoruz. Ortak set edilmiş değerler haricinde bu class’ımızda da farklı bir özellik bulunmasını istediğimiz için map görünümünü uydu görünümü şeklinde tanımlıyoruz.
layout kısmında ise değişen bir nokta bulunmamaktadır.
Buraya kadar anlattığımız kısımda kullandığımız map fragment’larımızı hep statik olarak tanımladık. Lakin sizler isterseniz bu map fragment’ları dinamik olarak class’ınızda çağırabilirsiniz. Yazımızın sonunda paylaşacağım github reposu üzerinde aslında ParentFragment class’ımız bir activity içinde dinamik olarak çağrılmış durumdadır. İsterseniz sizler aynı şekilde dinamik olarak kendi custom map fragment’ınızı çağırabilirsiniz.
Polyline Kullanımı
Volt Lines’ın hem sürücü hem de yolcu uygulamalarında aktif olarak rotaları gösterebilmek için polyline kullanmaktayız. Bizler polyline’ları kullanırken belli bir formatta gelen bu veriyi, oluşturduğumuz bir yapı ile decode ediyor ve ArrayList formatına çeviriyor sonrasında da birazdan örnek kod üzerinde de göreceğiniz addAll ile map üzerinde gösterimini sağlıyoruz. Fakat bu örneğimizde olayın mantığını anlamak adına basit gösterim gerçekleştireceğiz.
LatLng’lerden oluşan bir liste oluşturduk ve CustomMapFragment’ın içindeki addPolyLine function’nuna bunu gönderdik.
googleMap.addPolyline function’ı oluşturduktan sonra PolyLineOption yardımı ile addAll diyerek LatLng listemizi içine ekliyoruz sonrasında rengini ve float cinsinden genişliğini ekliyoruz.
Kodumuzu run ettiğimizde ekranda çok basit bir şekilde polyline’ı çizdirdiğimizi görüyoruz.
Emülatör veya test cihazınızdan kodu çalıştırdıysanız ve aynı zamanda Volt Lines uygulaması gibi harita/lokasyon bazlı bir uygulama daha önceden kullandıysanız fark edeceğiniz veya isteyeceğiniz bir ek nokta olabilir. Örneğin çizdirdiğimiz polyline’ı ekrana sığacak şekilde görebilmek. Bunu da LatLngBounds class’ı yardımı ile yapacağız.
Elimizde LatLng’lerin tamamını include function’nuna bir for döngüsü yardımı ile gönderelim. Daha sonrasında daha önceden de anlattığımız cameraMove function’u ile birlikte bu iş için kullanabileceğimiz CameraUpdateFactory.newLatLngBounds’ı içine .build() diyerek set edelim. Hatırlarsanız daha önceden CameraUpdateFactory ile birlikte newLatLngZoom ve zoomBy kullanmıştık, bu sefer de oluşturduğumuz bounds’u haritada göstermek için newLatLngBounds’u kullandık.
override fun polyLineBounds(coordinates: List<LatLng>) {
val boundsBuilder = LatLngBounds.Builder()
for (latLngPoint in coordinates) {
boundsBuilder.include(latLngPoint)
}
googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(boundsBuilder.build(), 70))
}
Custom Marker Kullanımı
Bizler Volt Lines’da marker’ları, yolcu indi/bindi noktaları ve yolcuların şirket konumlarını göstermek için kullanmaktayız. Her marker için kendi custom yarattığımız tipte ikonları kullanmaktayız. Çünkü bu marker’lar yolculuk sırasını temsil eden numaralandırlamaları gösterdiği gibi arka planda bizler için de birer object tutuculardır. Buradaki örneğimiz için bu kadar komplike bir yapı oluşturmayacağız. Lakin kendi custom marker’larınızı nasıl haritada gösterebileceğini basit bir şekilde örneklendirmiş olacağız.
Yazının başında marker yapısını ve nasıl eklendiğini görmüştünüz. Eğer projenizi run ettiyseniz default bir kırmızı marker görmüşsünüzdür. Bunun yerine kendi custom marker’larımızı oluşturalım.
Yapacağımız örnekte iki tip custom marker kullanacağız. Birincisi drawable kullanarak, diğeri ise oluşturacağımız bir view class ile kullanacağız. View class ile de bir örnek yapmamızın sebebi, eğer bizlerin birden fazla marker’ı olacaksa ve bu marker’ların içine yazı veya başka component’ler eklenecekse, bu işleri yapabilmenin en mantıklı yolu oluşturacağımız bir view class’ı marker olarak kullanmaktır. Eğer elimizdeki bir drawable’ı map üzerinde göstermek istiyorsak, direkt olarak bu drawable’ı olduğu gibi kullanıp marker olarak kullanabiliriz.
İlk olarak bu işlemler için oluşturduğum ImageUtils class’ımıza bakalım
Haritada bir marker göstermek için MarkerOptions kullanmamız gerektiğinden return tipi MarkerOptions olan iki adet function yarattık. Bu function’lardan biri view class diğeri ise drawable içindir. Burada sizlere farklı gelen tek şey ikon içine set ederken yaptıklarımızdır. View class ve drawable’ı ikonun içine set edebilmemiz için bu iki değeri de BitmapDescriptor’a dönüştürmemiz gereklidir. BitmapDescriptor’a dönüştürebilmek için de ilk başta bunları Bitmap’e dönüştürmemiz gereklidir. Dönüşüm işlemlerinin detaylarına konumuz ile alakalı olmadığı için girmeyeceğim ama kendiniz de farklı bir tipten bitmap’e dönüşüm yapmak için aşağıdaki kodu veya farklı kaynaklardan biraz daha farklı yöntemleri bulup kullanabilirsiniz.
Yarattığımız basit view class’ımızın da kodları aşağıdadır. Sizler isterseniz farklı component’ler ile ya da bir kart oluşturup bunun içinde imageview ve textview’lar ile aslında map üzerinde bilgi kartları gösterebilirsiniz.
MapsActivity üzerinden addMapMarker function’ın içine yukarıdaki generate function’larımızı set ediyoruz.
mapFragment.addMapMarker(ImageUtils.generateMarkerOptionsWithView(this))
//mapFragment.addMapMarker(ImageUtils.generateMarkerOptionsWithDrawable(this))
CustomMapFragment’ın içinde yarattığımız addMapMarker function’ın içinde de gönderdiğimiz markerOptions’ı googleMap.addMarker(markerOptions) diyerek map üzerinde gösterimini sağlıyoruz.
Yazıyı her ne kadar yeni başlayanlar için kolay ve kısa tutmayı hedeflediysem de sadece kolay kısmında başarılı olduğumu düşünüyorum :D Lakin map kullanımına yeni başlayanlar için detaylı ve basit örnekler ile sektörde nasıl kullanıldığını sizlere sunduğumu düşünüyorum.
Konu hakkında bu makale üzerinden bana ulaşabileceğiniz gibi suleyman.kinik@voltlines.com mail adresinden de beni dürtebilirsiniz.
Yazıda kullandığım kodlara da github repomdan ulaşabilirsiniz.