Skip to main content

RecyclerView

MapView integration inside a RecyclerView.
Android Examples App Available

This example code is part of the Maps SDK for Android Examples App, a working Android project available on GitHub. Android developers are encouraged to run the examples app locally to interact with this example in an emulator and explore other features of the Maps SDK.

See our Run the Maps SDK for Android Examples App tutorial for step-by-step instructions.

SurfaceRecyclerViewActivity.kt
package com.mapbox.maps.testapp.examples

import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.mapbox.maps.MapView
import com.mapbox.maps.Style
import com.mapbox.maps.plugin.gestures.gestures
import com.mapbox.maps.testapp.R
import com.mapbox.maps.testapp.databinding.ActivityRecyclerBinding

/**
* Test activity showcasing how to integrate multiple SurfaceView MapViews in a RecyclerView.
*
* It requires calling the correct lifecycle methods when detaching and attaching the View to
* the RecyclerView with onViewAttachedToWindow and onViewDetachedFromWindow.
*
*/
@SuppressLint("ClickableViewAccessibility")
class SurfaceRecyclerViewActivity : AppCompatActivity() {

private lateinit var mapView: MapView

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityRecyclerBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = ItemAdapter(this, LayoutInflater.from(this))
}

fun getMapItemLayoutId(): Int {
return R.layout.item_map
}

class ItemAdapter(
private val activity: SurfaceRecyclerViewActivity,
private val inflater: LayoutInflater
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

private val items = List(75) {
if (it == 4)
MapItem(Style.STANDARD)
else
"Row $it"
}

private var mapHolders: MutableList<MapHolder> = mutableListOf()

companion object {
const val TYPE_MAP = 0
const val TYPE_TEXT = 1
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == TYPE_MAP) {
activity.mapView = inflater.inflate(activity.getMapItemLayoutId(), parent, false) as MapView
val mapHolder = MapHolder(activity.mapView)
mapHolders.add(mapHolder)
return mapHolder
} else {
TextHolder(inflater.inflate(android.R.layout.simple_list_item_1, parent, false) as TextView)
}
}

override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
super.onViewAttachedToWindow(holder)
if (holder is MapHolder) {
val mapView = holder.mapView
mapView.onStart()
}
}

override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
super.onViewDetachedFromWindow(holder)
if (holder is MapHolder) {
val mapView = holder.mapView
mapView.onStop()
}
}

override fun getItemCount(): Int {
return items.count()
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is TextHolder) {
holder.bind(items[position] as String)
} else if (holder is MapHolder) {
holder.bind(items[position] as MapItem)
}
}

override fun getItemViewType(position: Int): Int {
return if (items[position] is MapItem) {
TYPE_MAP
} else {
TYPE_TEXT
}
}

data class MapItem(val style: String)
class MapHolder(val mapView: MapView) : RecyclerView.ViewHolder(mapView) {

init {
// unfortunately, if there are multiple maps hosted in one activity, state saving is not possible
mapView.setOnTouchListener { view, motionEvent ->
// Disallow the touch request for recyclerView scroll
view.parent.requestDisallowInterceptTouchEvent(true)
mapView.onTouchEvent(motionEvent)
true
}
}

fun bind(mapItem: MapItem) {
mapView.gestures.scrollEnabled = false
mapView.mapboxMap.loadStyle(mapItem.style)
}
}
}

class TextHolder(private val textView: TextView) : RecyclerView.ViewHolder(textView) {
fun bind(item: String) {
this.textView.text = item
}
}
}
Was this example helpful?