Search code examples
androidkotlingeojsonmapbox-android

Symbol layer icon size change Mapbox - Android dont work


I am trying to make an example in which when I click on a symbollayer it is expanded to know which one is pressed. I enter the data thanks to two geojson files that I created with Mapbox Studio. I tried to follow this examplehttps://docs.mapbox.com/android/maps/examples/icon-size-change-on-click/ but either none is zoomed or all of the same color are zoomed (same layer). Any ideas? What am I doing wrong? For now I am just trying to zoom those with the layer "first-layer-id". Thank you very much.

My code here.

package com.novadev.mapboxexample.marker

import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.mapbox.geojson.Feature
import com.mapbox.geojson.FeatureCollection
import com.mapbox.mapboxsdk.Mapbox
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.maps.MapView
import com.mapbox.mapboxsdk.maps.MapboxMap
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.style.layers.Property
import com.mapbox.mapboxsdk.style.layers.PropertyFactory
import com.mapbox.mapboxsdk.style.layers.SymbolLayer
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
import com.novadev.mapboxexample.R
import kotlinx.android.synthetic.main.activity_marker.*
import java.net.URI
import java.net.URISyntaxException


class MarkerGeojson : AppCompatActivity(),
    OnMapReadyCallback,
    MapboxMap.OnMapClickListener {

    private lateinit var mapboxMap: MapboxMap
    private lateinit var markerAnimator: ValueAnimator
    private var markerSelected = false



    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Mapbox access token is configured here. This needs to be called either in your application
        // object or in the same activity which contains the mapview.
        Mapbox.getInstance(this, getString(R.string.map_box_auth_key))
        // This contains the MapView in XML and needs to be called after the access token is configured.
        setContentView(R.layout.activity_marker)
        mapView.onCreate(savedInstanceState)
        mapView.getMapAsync(this)
        initListeners()

    }

    override fun onMapReady(mapboxMap: MapboxMap) {
        this.mapboxMap = mapboxMap
        getMap()
        mapboxMap.addOnMapClickListener(this)
    }

    override fun onMapClick(point: LatLng): Boolean {
        val pixel = mapboxMap.projection.toScreenLocation(point)
        val features = mapboxMap.queryRenderedFeatures(pixel,"first-layer-id")
        val selectedFeature = mapboxMap.queryRenderedFeatures(
            pixel, "selected-marker-layer"
        )

        mapboxMap.getStyle{ style->
            val selectedMarkerSymbolLayer =
                (style.getLayer("selected-marker-layer") as SymbolLayer)




            if (selectedFeature.size > 0 && markerSelected) false

            if (features.isEmpty()) if (markerSelected) {
                deselectMarker(selectedMarkerSymbolLayer)
            }else false

            val source: GeoJsonSource? = style.getSourceAs("selected-marker")
            source?.setGeoJson(
                FeatureCollection.fromFeatures(
                    arrayOf(
                        Feature.fromGeometry(
                            features[0].geometry()
                        )
                    )
                )
            )

            if (markerSelected) {
                deselectMarker(selectedMarkerSymbolLayer)
            }
            if (features.size > 0) {
                selectMarker(selectedMarkerSymbolLayer)
            }
            // Get the first feature within the list if one exist
            if (features.size > 0) {
                val feature = features[0]

                // Ensure the feature has properties defined
                for ((key, value) in feature.properties()!!.entrySet()) {
                    // Log all the properties
                    Log.d("TAG", String.format("%s = %s", key, value))
                    when (key) {
                        "NOMBRE" -> {
                            tvTitleMarker.text = value.toString()
                            cvInfo.visibility = View.VISIBLE
                        }
                        "TELEFONO" -> tvSubtitlemarker.text = value.toString()
                    }


                }

            }
        }

        return true
    }

    private fun initListeners() {
        ivClose.setOnClickListener {
            cvInfo.visibility = View.GONE
        }
    }

    private fun getMap() {
        mapboxMap.setStyle(
            Style.MAPBOX_STREETS
        ) {
            // Map is set up and the style has loaded. Now you can add data or make other map adjustments.
            geoJSONToMap(
                "first-source-id",
                "first-layer-id",
                "asset://madridmujeres.geojson",
                it
            )
            geoJSONToMap(
                "second-source-id",
                "second-layer-id",
                "asset://madridoficinascorreos.geojson",
                it
            )
        }
    }


    private fun drawableToBitmap (drawable : Drawable): Bitmap {
        if (drawable is BitmapDrawable) {
            return drawable.bitmap
        }

        var  bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
        var canvas =  Canvas(bitmap)
        drawable.setBounds(0, 0, canvas.width, canvas.height)
        drawable.draw(canvas)

        return bitmap
    }



    private fun geoJSONToMap(
        sourceId: String,
        layerId: String,
        asset_id: String,
        style: Style) {
        try {
            val source = GeoJsonSource(sourceId, URI(asset_id))
            style.addSource(source)
            if (layerId == "first-layer-id") {
                var icon = drawableToBitmap(this.resources.getDrawable(R.drawable.ic_location_purple))

                style.addImage("img", icon)
                val symbolLayer = SymbolLayer(layerId, sourceId)
                symbolLayer.withProperties(
                    PropertyFactory.iconImage("img"),
                    PropertyFactory.iconAllowOverlap(true),
                    PropertyFactory.iconOffset(arrayOf(0f, -9f)),
                    PropertyFactory.iconAnchor(Property.ICON_ANCHOR_BOTTOM),
                    PropertyFactory.iconIgnorePlacement(true)
                )
                style.addLayer(symbolLayer)

                val sourceMarker = GeoJsonSource("selected-marker")
                style.addSource(sourceMarker)
                val symbolLayerSelected = SymbolLayer("selected-marker-layer", "selected-marker")
                symbolLayerSelected.withProperties(
                    PropertyFactory.iconImage("img"),
                    PropertyFactory.iconAllowOverlap(true),
                    PropertyFactory.iconOffset(arrayOf(0f, -9f)),
                    PropertyFactory.iconAnchor(Property.ICON_ANCHOR_BOTTOM),
                    PropertyFactory.iconIgnorePlacement(true))
                style.addLayer(symbolLayerSelected)

            } else {
                style.addImage("$layerId marker", this.resources.getDrawable(R.drawable.ic_location_yellow))
                val symbolLayer = SymbolLayer(layerId, sourceId)
                symbolLayer.setProperties(
                    PropertyFactory.iconImage("$layerId marker"),
                    PropertyFactory.iconAllowOverlap(true),
                    PropertyFactory.iconAnchor(Property.ICON_ANCHOR_BOTTOM),
                    PropertyFactory.iconIgnorePlacement(true)
                )
                style.addLayer(symbolLayer)
            }

        } catch (e: URISyntaxException) {
            e.printStackTrace()
        }

    }

    private fun selectMarker(iconLayer: SymbolLayer) {
        markerAnimator = ValueAnimator()
        markerAnimator.setObjectValues(1f, 2f)
        markerAnimator.duration = 300
        markerAnimator.addUpdateListener { animator ->
            iconLayer.setProperties(
                PropertyFactory.iconSize(animator.animatedValue as Float)
            )
        }
        markerAnimator.start()
        markerSelected = true
    }

    private fun deselectMarker(iconLayer: SymbolLayer) {
        markerAnimator.setObjectValues(2f, 1f)
        markerAnimator.duration = 300
        markerAnimator.addUpdateListener { animator ->
            iconLayer.setProperties(
                PropertyFactory.iconSize(animator.animatedValue as Float)
            )
        }
        markerAnimator.start()
        markerSelected = false
    }


    // Add the mapView lifecycle to the activity's lifecycle methods
    public override fun onResume() {
        super.onResume()
        mapView!!.onResume()
    }

    override fun onStart() {
        super.onStart()
        mapView!!.onStart()
    }

    override fun onStop() {
        super.onStop()
        mapView!!.onStop()
    }

    public override fun onPause() {
        super.onPause()
        mapView!!.onPause()
    }

    override fun onLowMemory() {
        super.onLowMemory()
        mapView!!.onLowMemory()
    }

    override fun onDestroy() {
        super.onDestroy()
        mapView!!.onDestroy()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        mapView!!.onSaveInstanceState(outState)
    }

}

Solution

  • It looks as if you are not setting the GeoJSONsource for the selected marker layer.

    GeoJsonSource source = style.getSourceAs("selected-marker");
    if (source != null) {
    source.setGeoJson(FeatureCollection.fromFeatures(
    new Feature[]{Feature.fromGeometry(features.get(0).geometry())}));
    }

    By not setting the geoJSON source, the source will remain the geoJSON containing the FeatureCollection containing all markers. --> All markers will be expanded instead of just the one you have clicked on.