The Android maps adapter

Overview

MapMe

MapMe

Download Build Status

MapMe is an Android library for working with Maps. MapMe brings the adapter pattern to Maps, simplifying the management of markers and annotations.

MapMe supports both Google Maps and Mapbox

Download

//base dependency
compile 'nz.co.trademe.mapme:mapme:1.2.0'
  
//for Google Maps support
compile 'nz.co.trademe.mapme:googlemaps:1.2.0'
  
//for Mapbox support
compile 'nz.co.trademe.mapme:mapbox:1.2.0'

Usage

A simple MapsAdapter might look like this:

class MapsAdapter(context: Context, private val markers: List<MarkerData>) : GoogleMapMeAdapter(context) {

    fun onCreateAnnotation(factory: AnnotationFactory, position: Int, annotationType: Int): MapAnnotation {
        val item = this.markers[position]
        return factory.createMarker(item.getLatLng(), null, item.getTitle())
    }

    fun onBindAnnotation(annotation: MapAnnotation, position: Int, payload: Any) {
        if (annotation is MarkerAnnotation) {
            val item = this.markers[position]
            annotation.setTitle(item.getTitle())
        }
    }

    val itemCount: Int
        get() = markers.size()
}

Using the adapter in your view:

val adapter: MapMeAdapter = GoogleMapMeAdapter(context, items)
adapter.setOnAnnotationClickListener(this)

mapView.getMapAsync { googleMap ->
    //Attach the adapter to the map view once it's initialized
    adapter.attach(mapView, googleMap)
}

Dispatch data updates to the adapter:

// add new data and tell the adapter about it

items.addAll(myData)
adapter.notifyDataSetChanged()

// or with DiffUtil

val diff = DiffUtil.calculateDiff(myDiffCallback)
diff.dispatchUpdatesTo(adapter)

Click listeners

MapMe takes the pain out of click listeners too. No more setting tags on markers and trying to match a tag to your data when the click event is received.

MapMe has a setOnAnnotationClickListener method that will pass back a MapAnnotation containing the position of the item in the list of data:

mapsAdapter.setOnAnnotationClickListener(OnMapAnnotationClickListener { annotation ->
            //retrieve the data item based on the position
            val item = myData[annotation.position]
            
            //handle item click here
            
            true
        })

Info window clicks are handled in the same way.

Animations

While MapMe doesn't handle marker animations directly, it does provide a onAnnotationAdded method on the adapter that is called when a marker is added to the map.

This is the ideal place to start an animation.

For example, the following animates a markers alpha when it is added to the map:

override fun onAnnotationAdded(annotation: MapAnnotation) {
        if (annotation !is MarkerAnnotation) return

        ObjectAnimator.ofFloat(annotation, "alpha", 0f, 1f)
                .apply {
                    duration = 150
                    interpolator = DecelerateInterpolator()
                    start()
               }
}

Markers and Annotations

MapMe is based around the concept of Annotations. An annotation is anything displayed on the map.

The only annotation currently supported is Markers. We hope to support many more in the future.

We'd love PR's adding support for more annotations!

Multiple annotation types

More complex adapters can override getItemAnnotationType to work with multiple annotations. The annotation type is passed to onCreateAnnotation just like in a RecyclerView Adapter.

AnnotationFactory

MapMe differs from list adapters in that the creation of annotations must be left up to the map as they are not standard Android views.

The MapAdapter onCreateAnnotation method provides an AnnotationFactory as a parameter that must be used to create and return Map Annotations.

DiffUtil

As well as support for standard Adapter methods such as notifyDataSetChanged, and notifyItemInserted, MapMe supports (and recommends) DiffUtil.

DiffUtil is where the true power of MapMe comes into play. Simple manipulate the data set, calculate the diff and dispatch it to MapMe. The map will instantly reflect the data.

A DiffResult can be dispatched to the MapAdapter just as you would a RecyclerView:

DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new MarkerDiffCallback(this.markers, newMarkers));
diffResult.dispatchUpdatesTo(mapAdapter);

Why the adapter pattern?

Working with a few map markers is simple, but working with hundreds can become a mess of spaghetti code.

The adapter pattern provides a clear separation of data from the view, allowing the data to be manipulated freely without the concern of updating the view.

We think this is a pattern fits perfectly with maps.

Contributing

We love contributions, but make sure to checkout CONTRIBUTING.MD first!

Comments
  • Crash

    Crash

    After add library crash FATAL EXCEPTION: main java.lang.NoSuchMethodError: No static method zzb(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; in class Lcom/google/android/gms/common/internal/zzbo; or its super classes (declaration of 'com.google.android.gms.common.internal.zzbo com.google.firebase.provider.FirebaseInitProvider.attachInfo(Unknown Source)

    opened by vkropivko 11
  • IndexOutOfBoundsException with an empty list

    IndexOutOfBoundsException with an empty list

    When a MapAdapter is initialized with an empty list of items, it crashes.

    java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
        at java.util.ArrayList.get(ArrayList.java:437)
        at ca.llamabagel.transpo.features.map.MapAdapter.onCreateAnnotation(MapAdapter.kt:41)
        at nz.co.trademe.mapme.MapMeAdapter.createAnnotation(MapMeAdapter.kt:91)
        at nz.co.trademe.mapme.MapMeAdapter.applyUpdates(MapMeAdapter.kt:126)
        at nz.co.trademe.mapme.MapMeAdapter.consumePendingUpdateOperations$mapme_debug(MapMeAdapter.kt:514)
        at nz.co.trademe.mapme.MapMeAdapter$updateChildViewsRunnable$1.run(MapMeAdapter.kt:502)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:
        at android.app.ActivityThread.main(ActivityThread.java:
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
    
    opened by dellisd 5
  • androidX support

    androidX support

    Since MapMeAdapter inherits ListUpdateCallback from the legacy support library, the adapter cannot be used with androidX's DiffUtil.DiffResult.dispatchUpdatesTo().

    opened by dellisd 4
  • Double notifyDataSetChanged may cause crash

    Double notifyDataSetChanged may cause crash

    I don't know if it's a bad use of the library or not, but when performing the following sequence of actions, bad things can occur.

    1. Create a list with one item and create an adapter with it
    2. Call notifyDataSetChanged(). After that, getItemCount() gets called, returning 1 as result.
    3. Immediately, and before the adapter is able to refresh its annotations, remove the single item from the list
    4. Call notifyDataSetChanged(). After that, getItemCount() gets called, returning 0 as result.
    5. In the next view refresh, the adapter calls onCreateAnnotation(...) with position=0, leading to a crash since there are no items in the list.

    Apparently, the adapter remembers the first amount of annotations to be added to the map, but the second call to notifyDataSetChanged() does not get taken into account.

    opened by Gloix 4
  • googlemaps pom incorrect

    googlemaps pom incorrect

    Hi when updating to 1.0.5 for the google maps version the base dependency is not referenced correctly in the pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <modelVersion>4.0.0</modelVersion>
      <groupId>nz.co.trademe.mapme</groupId>
      <artifactId>googlemaps</artifactId>
      <version>1.0.5</version>
      <packaging>aar</packaging>
      <description>MapMe is an Android library that brings the adapter pattern to Maps, simplifying the management of markers and annotations.</description>
      <name>MapMe GoogleMaps</name>
      <url>https://github.com/TradeMe/MapMe.git</url>
      <licenses>
        <license>
          <name>MIT License</name>
          <url>http://www.opensource.org/licenses/mit-license.php</url>
          <distribution>repo</distribution>
        </license>
      </licenses>
      <scm>
        <url>https://github.com/TradeMe/MapMe.git</url>
      </scm>
      <dependencies>
        <dependency>
          <groupId>com.google.android.gms</groupId>
          <artifactId>play-services-maps</artifactId>
          <version>11.8.0</version>
        </dependency>
        <dependency>
          <groupId>com.android.support</groupId>
          <artifactId>appcompat-v7</artifactId>
          <version>27.0.1</version>
        </dependency>
        <dependency>
          <groupId>MapMe</groupId>
          <artifactId>mapme</artifactId>
          <version>unspecified</version>
        </dependency>
        <dependency>
          <groupId>org.jetbrains.kotlin</groupId>
          <artifactId>kotlin-stdlib-jre7</artifactId>
          <version>1.2.31</version>
        </dependency>
      </dependencies>
    </project>
    
    opened by aegis123 2
  • Add List adapters for simpler integration with DiffUtil

    Add List adapters for simpler integration with DiffUtil

    Since DiffUtil is usually used quite heavily with this library, I thought it might be useful to add an adapter with an interface similar to ListAdapter which greatly simplifies doing asynchronous diffs for an adapter.

    This implementation is based on ListAdapter and uses the AsyncListDiffer class to perform the diff and dispatch it to the adapter.

    Some tests still need to be written.

    opened by dellisd 0
  •  Clears pending updates when notifyDataSetChanged is called

    Clears pending updates when notifyDataSetChanged is called

    Fixes a crash caused by pending updates attempting to operate on an annotation list that is no longer there.

    This PR also updates the library to AGP 3.0.1 and updates some out of date dependencies.

    Fixes #17

    opened by josh-burton 0
  • Mocking framework

    Mocking framework

    Hi,

    hope find you well with this cold call.

    I am an author of mocking framework for Kotlin

    I see you are using mockito-kotlin.

    I just want you to be aware that there is solution that fully supports Kotlin and ask to try it in your new/current projects.

    I can help you if you answer to this issue.

    Thanks and please star it

    opened by oleksiyp 0
  • Removes map type information from MapAnnotation

    Removes map type information from MapAnnotation

    Removing the type from MapAnnotation greatly simplifies the API. The type was something the user didn’t need to know about, so isn’t required in the API.

    Removing it means we have to do a cast when interacting with the map in the annotation factory, but the annotation factory is typed so this is pretty safe.

    opened by josh-burton 0
  • Problems with KML and Annotation click

    Problems with KML and Annotation click

    Hi, I'm using Google Maps utils library to add a KML Layer to map.

    All works fine (both annotations and kml layers) but when I click on marker to open a bottomsheetdialog, the listener never called and the marker shows the info windows. If I disable the adding of KML, all works correctly.

    How can I fix?

    opened by CeccoCQ 0
  • `attach` now accepts a nullable `View` as it internally is used safely

    `attach` now accepts a nullable `View` as it internally is used safely

    The mapView is treated as Nullable throughout MapMeAdapter but when attaching, only a NonNull View is accepted. Even as SupportMapFragment is inflated in a parent's onCreateView, upon configuration changes onMapReady might be called before onCreateView of the parent so if the attaching is done in onMapReady the only possible valid View to pass is the one fetched by requireView() but that View has yet not been created and an IllegalException will be thrown.

    Instead if getView() that is Nullable would be allowed, things would work out.

    opened by c-b-h 0
  • Low performance on adding new items

    Low performance on adding new items

    Hi i use this lib for city directory app and it cause app lag. I measure performance and I got that these methods slow down app I share my logcat details

    I/Default-IBlockHandler: nz.co.trademe.mapme.MapAdapterHelper\dispatchSecondPass costed 3122 I/Default-IBlockHandler: nz.co.trademe.mapme.MapAdapterHelper\dispatch costed 3123 I/Default-IBlockHandler: nz.co.trademe.mapme.MapMeAdapter\applyUpdates costed 2155 I/Default-IBlockHandler: nz.co.trademe.mapme.MapMeAdapter\consumePendingUpdateOperations$mapme_release costed 5278 I/Default-IBlockHandler: nz.co.trademe.mapme.MapMeAdapter$updateChildViewsRunnable$1\run costed 5278

    as you see it took near 5.3 sec to update ui

    please help me

    opened by amirzeinaly 0
  • Custom animations (scale, rotate, translate) do not work?

    Custom animations (scale, rotate, translate) do not work?

    I would like to add a custom animation when markers are attached to the adapter. Following the provided sample code from the README, the alpha animation works perfectly on my created markers (https://github.com/TradeMe/MapMe#animations):

    override fun onAnnotationAdded(annotation: MapAnnotation) {
            if (annotation !is MarkerAnnotation) return
    
            ObjectAnimator.ofFloat(annotation, "alpha", 0f, 1f)
                    .apply {
                        duration = 150
                        interpolator = DecelerateInterpolator()
                        start()
                   }
    }
    

    However, when I try to implement a different animation, it doesn't seem to work, i.e. the markers simply pop up without any animation? I've tried translation, rotationand scale as follows:

    ObjectAnimator.ofFloat(annotation, "translationX", 100f).apply {
        duration = 1000
        start()
    }
    
    ObjectAnimator.ofFloat(annotation, "rotation", 360f).apply {
        duration = 1000
        start()
    }
    
    ObjectAnimator.ofFloat(annotation, "scaleX", 2f).apply {
        duration = 1000
        start()
    }
    

    Am I doing something wrong or is alpha the only supported animation on markers? Btw.: I am using the default google maps marker icon, i.e.:

    factory.createMarker(LatLng(item.lat, item.lon), null, item.title)
    
    opened by hiasel 0
Releases(1.2.1)
Owner
Trade Me
Trade Me
💡🚀⭐️ A generalized adapter for RecyclerView on Android which makes it easy to add heterogeneous items to a list

Mystique is a Kotlin library for Android’s RecyclerView which allows you to create homogeneous and heterogeneous lists effortlessly using an universal

Rahul Chowdhury 48 Oct 3, 2022
RecyclerView Adapter Library with different models and different layouts as convenient as possible.

RecyclerView Presenter Convenience library to handle different view types with different presenters in a single RecyclerView. How to install repositor

Jan Rabe 86 Dec 26, 2022
A simple and easy adapter for RecyclerView. You don't have to make adapters and view holders anymore. Slush will help you.

한국어 No more boilerplate adapters and view holders. Slush will make using RecyclerView easy and fast. The goal of this project is to make RecyclerView,

SeungHyun 26 Sep 13, 2022
Don't write a RecyclerView adapter again. Not even a ViewHolder!

LastAdapter Don't write a RecyclerView adapter again. Not even a ViewHolder! Based on Android Data Binding Written in Kotlin No need to write the adap

Miguel Ángel Moreno 781 Dec 19, 2022
Adapter library for SharedPreferences

EasyPrefs Adapter library for SharedPreferences which reduces boilerplate needed to store simple data, but open enough to not interfere with your own

Kacper Wojciechowski 6 Nov 23, 2021
Android MVVM framework write in kotlin, develop Android has never been so fun.

KBinding 中文版 Android MVVM framework write in kotlin, base on anko, simple but powerful. It depends on my another project AutoAdapter(A library for sim

Benny 413 Dec 5, 2022
Klimatic is an android app built using Kotlin. It try to showcase all the latest technologies used in android.

Klimatic Klimatic is an android app built using Kotlin. It try to showcase all the latest technologies used in android. Built using Android Architectu

Shivam Satija 34 Oct 11, 2022
Oratio Library for Android Studio helps you simplify your Android TTS codes

Oratio Oratio is a library for Android Studio. This library is useful to a number of developers who are currently making apps using android TTS(Text-T

Jacob Lim 1 Oct 28, 2021
This is a demo android app representing implementation of SE principles in android app development

Articles Demo This repository contains a sample Android App that shows most popular articles data from NY Times API. This is a sample app that shows h

Waesem Abbas 2 Jan 20, 2022
Android-Boilerplate - Base project for android development with new technology

Android-Boilerplate Base project for android development with new technology, in

Muhammad Rizky Arifin 1 Aug 15, 2022
Gits-android-extensions - A collection of Kotlin extensions to simplify Android development

gits-android-extensions A collection of Kotlin extensions to simplify Android de

GITS Indonesia 3 Feb 3, 2022
Android Clean Architecture in Rorty is a sample project that presents modern, approach to Android application development using Kotlin and latest tech-stack.

Android Clean Architecture in Rorty is a sample project that presents modern, approach to Android application development using Kotlin and latest tech-stack.

Mr.Sanchez 176 Jan 4, 2023
Android Ptrace Inject for all ABIs and all APIs. Help you inject Shared Library on Android.

Android Ptrace Inject 中文可以参考我的注释内容进行理解 我写的注释相对来说比较全面了 How to build Make sure you have CMake and Ninja in your PATH Edit CMakeLists.txt. Set ANDROID_ND

SsageParuders 65 Dec 19, 2022
Pleasant Android application development

⚠️ Anko is deprecated. Please see this page for more information. Anko is a Kotlin library which makes Android application development faster and easi

Kotlin 15.9k Jan 5, 2023
YouTube Player library for Android and Chromecast, stable and customizable.

android-youtube-player android-youtube-player is a stable and customizable open source YouTube player for Android. It provides a simple View that can

Pierfrancesco Soffritti 2.9k Jan 2, 2023
A highly customizable calendar library for Android, powered by RecyclerView.

CalendarView A highly customizable calendar library for Android, powered by RecyclerView. With this library, your calendar will look however you want

Kizito Nwose 3.4k Jan 3, 2023
View "injection" library for Android.

Kotter Knife Deprecated: This was a terrible idea because it allocates an object for every view reference. Do not use, and do not use anything like it

Jake Wharton 2.2k Dec 28, 2022
Android library that creates app shortcuts from annotations

Shortbread Android library that generates app shortcuts for activities and methods annotated with @Shortcut. No need to touch the manifest, create XML

Matthias Robbers 1.8k Dec 30, 2022
Android + Kotlin + Github Actions + ktlint + Detekt + Gradle Kotlin DSL + buildSrc = ❤️

kotlin-android-template ?? A simple Github template that lets you create an Android/Kotlin project and be up and running in a few seconds. This templa

Nicola Corti 1.5k Jan 3, 2023