Map module: review comments and small fixes
This commit is contained in:
parent
c8c44ede4f
commit
3f44ad3ba7
|
|
@ -43,7 +43,7 @@ abstract class AbstractMapManager<TMapView : View, TMap : Any, TLocation : Any>(
|
|||
|
||||
abstract fun increaseZoom(target: TLocation, zoomIncreaseValue: Int = getDefaultZoomStep())
|
||||
|
||||
abstract fun decreaseZoom(target: TLocation, zoomIncreaseValue: Int = getDefaultZoomStep())
|
||||
abstract fun decreaseZoom(target: TLocation, zoomDecreaseValue: Int = getDefaultZoomStep())
|
||||
|
||||
abstract fun setMapAllGesturesEnabled(enabled: Boolean)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,28 +17,24 @@ open class GoogleIconGenerator<T : ClusterItem>(
|
|||
private val context: Context
|
||||
) : IconGenerator(context), BaseIconGenerator<T, Cluster<T>, BitmapDescriptor> {
|
||||
|
||||
init {
|
||||
setBackground(ContextCompat.getDrawable(context, R.drawable.default_cluster_background))
|
||||
LayoutInflater
|
||||
.from(context)
|
||||
.inflate(R.layout.view_google_map_cluster_item, null)
|
||||
.apply {
|
||||
setContentView(this)
|
||||
}
|
||||
}
|
||||
|
||||
private val clusterIconsCache = SparseArray<BitmapDescriptor>()
|
||||
private val clusterItemIconsCache = mutableMapOf<T, BitmapDescriptor>()
|
||||
|
||||
fun setDefaultViewAndBackground() {
|
||||
val defaultLayout = LayoutInflater.from(context).inflate(R.layout.view_google_map_cluster_item, null)
|
||||
setBackground(ContextCompat.getDrawable(context, R.drawable.default_cluster_background))
|
||||
setContentView(defaultLayout)
|
||||
}
|
||||
|
||||
override fun getClusterIcon(cluster: Cluster<T>): BitmapDescriptor? {
|
||||
val clusterSize = cluster.size
|
||||
return BitmapDescriptorFactory.fromBitmap(makeIcon(clusterSize.toString()))
|
||||
}
|
||||
|
||||
override fun getClusterItemIcon(clusterItem: T): BitmapDescriptor? =
|
||||
context.getDrawable(ru.touchin.basemap.R.drawable.marker_default_icon)?.let {
|
||||
BitmapDescriptorFactory.fromBitmap(it.toBitmap())
|
||||
}
|
||||
override fun getClusterItemIcon(clusterItem: T): BitmapDescriptor? {
|
||||
val defaultIcon = context.getDrawable(ru.touchin.basemap.R.drawable.marker_default_icon)
|
||||
return BitmapDescriptorFactory.fromBitmap(defaultIcon?.toBitmap())
|
||||
}
|
||||
|
||||
override fun getClusterItemView(clusterItem: T): BitmapDescriptor? =
|
||||
clusterItemIconsCache.getOrPutIfNotNull(clusterItem) { getClusterItemIcon(clusterItem) }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package ru.touchin.googlemap
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import com.google.android.gms.maps.GoogleMap
|
||||
import com.google.android.gms.maps.model.BitmapDescriptor
|
||||
import com.google.android.gms.maps.model.MarkerOptions
|
||||
|
|
@ -19,10 +18,7 @@ open class GoogleMapItemRenderer<TClusterItem : ClusterItem>(
|
|||
) : DefaultClusterRenderer<TClusterItem>(context, googleMap, clusterManager) {
|
||||
|
||||
var iconGenerator: BaseIconGenerator<TClusterItem, Cluster<TClusterItem>, BitmapDescriptor> =
|
||||
GoogleIconGenerator<TClusterItem>(context).apply {
|
||||
setBackground(context.getDrawable(R.drawable.default_cluster_background))
|
||||
setContentView(LayoutInflater.from(context).inflate(R.layout.view_google_map_cluster_item, null))
|
||||
}
|
||||
GoogleIconGenerator<TClusterItem>(context).apply { setDefaultViewAndBackground() }
|
||||
|
||||
override fun shouldRenderAsCluster(cluster: Cluster<TClusterItem>): Boolean =
|
||||
cluster.size > minClusterItemSize
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class GoogleMapManager(mapView: MapView) : AbstractMapManager<MapView, GoogleMap
|
|||
|
||||
override fun initialize(mapListener: AbstractMapListener<MapView, GoogleMap, LatLng>?) {
|
||||
super.initialize(mapListener)
|
||||
mapView.getMapAsync(::initMap)
|
||||
mapView.getMapAsync(this::initMap)
|
||||
}
|
||||
|
||||
override fun initMap(map: GoogleMap) {
|
||||
|
|
|
|||
|
|
@ -12,18 +12,20 @@ import com.google.maps.android.clustering.algo.Algorithm
|
|||
import com.google.maps.android.clustering.algo.NonHierarchicalDistanceBasedAlgorithm
|
||||
import com.google.maps.android.clustering.algo.PreCachingAlgorithmDecorator
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.flow.sample
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
|
||||
class GooglePlacemarkManager<TClusterItem : ClusterItem>(
|
||||
context: Context,
|
||||
private val lifecycleOwner: LifecycleOwner,
|
||||
|
|
@ -47,7 +49,8 @@ class GooglePlacemarkManager<TClusterItem : ClusterItem>(
|
|||
|
||||
private val markers = mutableListOf<TClusterItem>()
|
||||
private var lastVisibleItems = emptyList<TClusterItem>()
|
||||
private var onCameraIdleListener: (() -> Unit)? = null
|
||||
|
||||
var onCameraIdleListener: (() -> Unit)? = null
|
||||
|
||||
var clusterRenderer: GoogleMapItemRenderer<TClusterItem>? = null
|
||||
set(value) {
|
||||
|
|
@ -55,8 +58,6 @@ class GooglePlacemarkManager<TClusterItem : ClusterItem>(
|
|||
setRenderer(value)
|
||||
}
|
||||
|
||||
private val lock = Any()
|
||||
|
||||
init {
|
||||
googleMap.setOnCameraIdleListener(this)
|
||||
googleMap.setOnMarkerClickListener(this)
|
||||
|
|
@ -65,40 +66,28 @@ class GooglePlacemarkManager<TClusterItem : ClusterItem>(
|
|||
setOnClusterItemClickListener(clusterItemTapAction)
|
||||
}
|
||||
|
||||
fun setItems(items: Collection<TClusterItem>) {
|
||||
synchronized(lock) {
|
||||
markers.clear()
|
||||
markers.addAll(items)
|
||||
onDataChanged()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun addItems(items: Collection<TClusterItem>) {
|
||||
synchronized(lock) {
|
||||
markers.addAll(items)
|
||||
onDataChanged()
|
||||
}
|
||||
markers.addAll(items)
|
||||
onDataChanged()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun addItem(clusterItem: TClusterItem) {
|
||||
synchronized(lock) {
|
||||
markers.add(clusterItem)
|
||||
onDataChanged()
|
||||
}
|
||||
markers.add(clusterItem)
|
||||
onDataChanged()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun removeItem(atmClusterItem: TClusterItem) {
|
||||
synchronized(lock) {
|
||||
markers.remove(atmClusterItem)
|
||||
onDataChanged()
|
||||
}
|
||||
markers.remove(atmClusterItem)
|
||||
onDataChanged()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun clearItems() {
|
||||
synchronized(lock) {
|
||||
markers.clear()
|
||||
onDataChanged()
|
||||
}
|
||||
markers.clear()
|
||||
onDataChanged()
|
||||
}
|
||||
|
||||
override fun onCameraIdle() {
|
||||
|
|
@ -106,22 +95,11 @@ class GooglePlacemarkManager<TClusterItem : ClusterItem>(
|
|||
onCameraIdleEvent.tryEmit(true)
|
||||
}
|
||||
|
||||
private fun onDataChanged() {
|
||||
onVisibilityChangedEvent.tryEmit(getData())
|
||||
}
|
||||
|
||||
private fun getData(): Pair<VisibleRegion?, List<TClusterItem>> =
|
||||
googleMap.projection.visibleRegion to markers
|
||||
|
||||
private fun listenToCameraIdleEvents() {
|
||||
cameraIdleJob = lifecycleOwner.lifecycleScope.launchWhenStarted {
|
||||
onCameraIdleEvent
|
||||
.debounce(CAMERA_DEBOUNCE_MILLI)
|
||||
.flowOn(Dispatchers.Main)
|
||||
.collect {
|
||||
onCameraIdleListener?.invoke()
|
||||
}
|
||||
}
|
||||
@Synchronized
|
||||
fun setItems(items: Collection<TClusterItem>) {
|
||||
markers.clear()
|
||||
markers.addAll(items)
|
||||
onDataChanged()
|
||||
}
|
||||
|
||||
fun startClustering() {
|
||||
|
|
@ -131,10 +109,7 @@ class GooglePlacemarkManager<TClusterItem : ClusterItem>(
|
|||
.debounce(CLUSTERING_START_DEBOUNCE_MILLI)
|
||||
.flowOn(Dispatchers.Default)
|
||||
.onStart { emit(getData()) }
|
||||
.filter { (visibleRegion, _) -> visibleRegion != null }
|
||||
.map { (visibleRegion, clusteringItems) ->
|
||||
clusteringItems.filter { visibleRegion?.latLngBounds?.contains(it.position) == true }
|
||||
}
|
||||
.mapNotNull { (region, items) -> findItemsInRegion(region, items) }
|
||||
.sample(CLUSTERING_NEW_LIST_CONSUMING_THROTTLE_MILLIS)
|
||||
.catch { emit(lastVisibleItems) }
|
||||
.flowOn(Dispatchers.Main)
|
||||
|
|
@ -148,16 +123,32 @@ class GooglePlacemarkManager<TClusterItem : ClusterItem>(
|
|||
listenToCameraIdleEvents()
|
||||
}
|
||||
|
||||
private fun listenToCameraIdleEvents() {
|
||||
cameraIdleJob = lifecycleOwner.lifecycleScope.launchWhenStarted {
|
||||
onCameraIdleEvent
|
||||
.debounce(CAMERA_DEBOUNCE_MILLI)
|
||||
.flowOn(Dispatchers.Main)
|
||||
.collect {
|
||||
onCameraIdleListener?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun stopClustering() {
|
||||
clusteringJob?.cancel()
|
||||
cameraIdleJob?.cancel()
|
||||
}
|
||||
|
||||
fun setOnCameraIdleListener(listener: () -> Unit) {
|
||||
if (onCameraIdleListener != null) return
|
||||
onCameraIdleListener = listener
|
||||
private fun onDataChanged() {
|
||||
onVisibilityChangedEvent.tryEmit(getData())
|
||||
}
|
||||
|
||||
private fun getData(): Pair<VisibleRegion?, List<TClusterItem>> =
|
||||
googleMap.projection.visibleRegion to markers
|
||||
|
||||
private fun findItemsInRegion(region: VisibleRegion?, items: List<TClusterItem>): List<TClusterItem>? =
|
||||
region?.let { items.filter { item -> item.position in region.latLngBounds } }
|
||||
|
||||
private companion object {
|
||||
const val CAMERA_DEBOUNCE_MILLI = 50L
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ import com.yandex.runtime.ui_view.ViewProvider
|
|||
class DefaultIconGenerator<T : PointModel>(private val context: Context) : YandexIconGenerator<T>() {
|
||||
|
||||
override fun getClusterIcon(cluster: List<T>): ViewProvider {
|
||||
val view: TextView = LayoutInflater.from(context).inflate(R.layout.default_cluster_view, null) as TextView
|
||||
view.setText(cluster.size.toString())
|
||||
view.setBackgroundResource(ru.touchin.basemap.R.drawable.marker_default_icon)
|
||||
|
||||
return ViewProvider(view)
|
||||
val textView = LayoutInflater.from(context).inflate(R.layout.default_cluster_view, null).apply {
|
||||
(this as? TextView)?.text = cluster.size.toString()
|
||||
setBackgroundResource(ru.touchin.basemap.R.drawable.marker_default_icon)
|
||||
}
|
||||
return ViewProvider(textView)
|
||||
}
|
||||
|
||||
override fun getClusterItemIcon(clusterItem: T) = ViewProvider(
|
||||
|
|
|
|||
|
|
@ -135,10 +135,12 @@ class YandexMapManager(
|
|||
}
|
||||
|
||||
override fun setMapAllGesturesEnabled(enabled: Boolean) {
|
||||
map.isRotateGesturesEnabled = enabled
|
||||
map.isScrollGesturesEnabled = enabled
|
||||
map.isTiltGesturesEnabled = enabled
|
||||
map.isZoomGesturesEnabled = enabled
|
||||
with(map) {
|
||||
isRotateGesturesEnabled = enabled
|
||||
isScrollGesturesEnabled = enabled
|
||||
isTiltGesturesEnabled = enabled
|
||||
isZoomGesturesEnabled = enabled
|
||||
}
|
||||
}
|
||||
|
||||
override fun setMyLocationEnabled(enabled: Boolean) {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@ class YandexPlacemarkManager<TPoint : PointModel>(
|
|||
private val markerTapAction: (MapObject, Point) -> Boolean,
|
||||
) : ClusterListener, ClusterTapListener, MapObjectTapListener {
|
||||
|
||||
private companion object {
|
||||
const val DEFAULT_CLUSTER_RADIUS = 42.0
|
||||
const val DEFAULT_MIN_ZOOM = 35
|
||||
}
|
||||
|
||||
private val markers = mutableListOf<TPoint>()
|
||||
private var placemarkCollection: ClusterizedPlacemarkCollection? = null
|
||||
|
||||
|
|
@ -25,8 +30,8 @@ class YandexPlacemarkManager<TPoint : PointModel>(
|
|||
|
||||
fun addMarkersOnMap(
|
||||
mapView: MapView,
|
||||
clusterRadius: Double = 42.0,
|
||||
minZoom: Int = 35
|
||||
clusterRadius: Double = DEFAULT_CLUSTER_RADIUS,
|
||||
minZoom: Int = DEFAULT_MIN_ZOOM
|
||||
) {
|
||||
removeMarkers()
|
||||
|
||||
|
|
@ -52,9 +57,8 @@ class YandexPlacemarkManager<TPoint : PointModel>(
|
|||
}
|
||||
|
||||
override fun onClusterAdded(cluster: Cluster) {
|
||||
mapItemRenderer.getClusterIcon(cluster.toPlacemarkList())?.let {
|
||||
cluster.appearance.setView(it)
|
||||
}
|
||||
val clusterIcon = mapItemRenderer.getClusterIcon(cluster.toPlacemarkList())
|
||||
clusterIcon?.let(cluster.appearance::setView)
|
||||
cluster.addClusterTapListener(this)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue