Custom Marker icon using layout in Android.

Recently I was working on an app where I need to draw markers with images of users on the map I googled it and found some solutions and almost all of these solutions are using canvas to draw that kind of custom markers.I was thinking there must be an easier way to do it like converting a layout into the marker and add it to the map. So, in this post, I will show you how to do that.

For creating a custom marker create a layout file where we will describe how our custom marker will look like.

view_custom_marker.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
android:background="@drawable/marker_mask">

<ImageView
  android:id="@+id/profile_image"
  android:layout_width="48dp"
  android:layout_height="48dp"
  android:layout_gravity="center_horizontal"
  android:contentDescription="@null"
  android:src="@drawable/avatar" />
</FrameLayout>

First inflate the viw_custom_marker.xml file.

mCustomMarkerView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.view_custom_marker, null);
 

Now we will write a method which will take the mCustomMarkerView and drawable resId which you want to show on map and convert it into a bitmap.

/**
* @param view is custom marker layout which we will convert into bitmap.
* @param resId is the drawable which you want to show in marker.
* @return
*/
private Bitmap getMarkerBitmapFromView(View view, @DrawableRes int resId) {

  mMarkerImageView.setImageResource(resId);
  view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
  view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
  view.buildDrawingCache();
  Bitmap returnedBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),
          Bitmap.Config.ARGB_8888);
  Canvas canvas = new Canvas(returnedBitmap);
  canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC_IN);
  Drawable drawable = view.getBackground();
  if (drawable != null)
      drawable.draw(canvas);
  view.draw(canvas);
  return returnedBitmap;
}
private void addCustomMarkerFromDrawable() {

  if (mGoogleMap == null) {
      return;
  }
  // adding a marker on map with image from  drawable
  mGoogleMap.addMarker(new MarkerOptions()
          .position(mDummyLatLng)
          .icon(BitmapDescriptorFactory.fromBitmap(getMarkerBitmapFromView(mCustomMarkerView,R.drawable.avatar))));

}

I am sure you guys must have a question in your mind what if I want to load an image from the server using URL and show it on the map. For that, you can use the following code snippet which takes bitmap as an input parameter.

Note: For loading an image from url and converting it into a bitmap you can use Glide, Picasso.

/**
* @param view is custom marker layout which we will convert into bitmap.
* @param bitmap is the image which you want to show in marker.
* @return
*/
private Bitmap getMarkerBitmapFromView(View view, Bitmap bitmap) {

  mMarkerImageView.setImageBitmap(bitmap);
  view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
  view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
  view.buildDrawingCache();
  Bitmap returnedBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),
          Bitmap.Config.ARGB_8888);
  Canvas canvas = new Canvas(returnedBitmap);
  canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC_IN);
  Drawable drawable = view.getBackground();
  if (drawable != null)
      drawable.draw(canvas);
  view.draw(canvas);
  return returnedBitmap;

}
private void addCustomMarkerFromURL() {

  if (mGoogleMap == null) {
      return;
  }
  // adding a marker with image from URL using glide image loading library
  Glide.with(getApplicationContext())
  .load(ImageUrl).asBitmap().fitCenter()
  .into(new SimpleTarget<Bitmap>() {
      @Override
      public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation) {

        mGoogleMap.addMarker(new MarkerOptions().position(mDummyLatLng)
        .icon(BitmapDescriptorFactory.fromBitmap(getMarkerBitmapFromView(mCustomMarkerView, bitmap))));

        mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(mDummyLatLng, 13f));

      }
  });

}
              

Now we just need to call the addCustomMarkerFromDrawable or addCustomMarkerFromURL in onMapReady callback.

@Override
public void onMapReady(GoogleMap googleMap) {

  mGoogleMap = googleMap;
  MapsInitializer.initialize(this);
  addCustomMarkerFromDrawable();
  //addCustomMarkerFromURL();
}

Get CustomMarkerDemo on GitHub


© 2022 Waleed Sarwar. All rights reserved.