2

I'm trying to implement a custom map marker using my XML layout into Google Maps.

However; when i use the createCustomMarker method to print out my custom marker into Google Maps, it does not load/show the image coming from the cloud/server.

I think it's because Glide(or the app in this matter) didn't get the change to finish downloading and rendering the image before the layout got converted into Bitmap, or maybe my implementation is just wrong. Can anyone help me with this?

@SuppressLint("InflateParams")
    private fun createCustomMarker(urlImageFromCloud: String): Bitmap{

        val marker: LayoutInflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val view: View = marker.inflate(R.layout.map_marker, null)

        val messageIcon: Int = resources.getIdentifier("local_image_from_drawable", "drawable", this.packageName)
        val markerPhoto: CircleImageView = view.findViewById(R.id.map_photo)
        val markerContainer: CircleImageView = view.findViewById(R.id.map_photo)
        val options: RequestOptions = RequestOptions()
            .centerCrop()
            .placeholder(R.color.colorGrayWhite)
            .error(R.color.colorGrayWhite)
            .diskCacheStrategy(DiskCacheStrategy.ALL)
        Glide.with(this)
            .load(urlImageFromCloud) // String image URL from my server/cloud - this is the part that does not show up.
            .apply(options).into(markerPhoto)
        Glide.with(this)
            .load(messageIcon)
            .apply(options).into(markerContainer)


        val displayMetrics = DisplayMetrics()
        windowManager.defaultDisplay.getMetrics(displayMetrics)

        view.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
        view.measure(displayMetrics.widthPixels, displayMetrics.heightPixels)
        view.layout(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels)
        view.buildDrawingCache()
        val bitmap = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        view.draw(canvas)

        return bitmap
    }

My map_marker XML :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/custom_marker_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

    <ImageView
            android:id="@+id/map_container"
            android:layout_width="75dp"
            android:layout_height="75dp"/>

    <de.hdodenhof.circleimageview.CircleImageView
            android:id="@+id/map_photo"
            android:src="@color/colorGray"
            android:layout_marginTop="5dp"
            android:layout_centerHorizontal="true"
            style="@style/MapMarkerCircleImage"/>


</RelativeLayout>

This is how i called my createCustomMarker method.

val defaultLocation = LatLng(locationLatitude, locationLongitude)
googleMap.addMarker(MarkerOptions().position(defaultLocation).icon(BitmapDescriptorFactory.fromBitmap(createCustomMarker("my_image_url_from_cloud"))))
dalemncy
  • 609
  • 8
  • 26
  • Apparently, the problem is `BitmapDescriptorFactory.fromBitmap` don't take the layer added by Glide.into, everything should work ok if you download the bitmap using Glide.asBitmap – Max Cruz May 29 '19 at 11:43

2 Answers2

2

I had the same issue. My solution was just to download the bitmap using Glide and with a listener create the marker when the download is complete.

private fun getMarkerIcon(context: Context, url: String, listener: (BitmapDescriptor) -> Unit) {
    val markerView = View.inflate(context, R.layout.view_marker, null)
    Glide.with(context)
        .asBitmap()
        .load(url)
        .into(object : SimpleTarget<Bitmap>() {

            override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                markerView.avatarImageView.setImageBitmap(resource)
                listener.invoke(BitmapDescriptorFactory.fromBitmap(getBitmapFromView(markerView)))
            }
        })
}

private fun getBitmapFromView(view: View): Bitmap {
    view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
    val bitmap = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    view.layout(0, 0, view.measuredWidth, view.measuredHeight)
    view.draw(canvas)
    return bitmap
}

And the call

getMarkerIcon(context, "http://....") {
    val options = MarkerOptions()
        .position(LatLng(latitude, longitude))
        .icon(it)
    googleMap.addMarker(options)
}
Max Cruz
  • 1,215
  • 13
  • 17
1

You can create a custom ImageView and get the BitmapDescriptor from it.

class CustomImageView @JvmOverloads constructor(context: Context,
                                                attrs: AttributeSet? = null,
                                                defStyle: Int = 0,
                                                defStyleRes: Int = 0): ImageView(context, attrs, defStyle, defStyleRes) {

    init {
        setImageBitmap(createCustomMarker("my_image_url_from_cloud"))
    }

    private fun loadBitmapFromView(view: View): Bitmap {
        view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
        val bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),
                Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight())
        view.draw(canvas)
        return bitmap
    }

    fun getBitmapDescriptor(): BitmapDescriptor {
        val bitmap = CommonUtil.loadBitmapFromView(this)
        return BitmapDescriptorFactory.fromBitmap(bitmap)
    }
}

Just get sure you loaded the image into the view before getting the BitmapDescriptor.

I got the functions from this answer.

kike
  • 4,255
  • 5
  • 23
  • 41