How can I create a speech-bubble border for a Google Marker Custom Icon using Picasso?
Asked Answered
B

4

11

How can I use Picasso and Google Marker Custom Icon to achieve this feature?

enter image description here

I know how to use Picasso for the image, but I don't know how to add that "marker icon" on the bottom and the borders.

Picasso.with(mContext)
            .load(url)
            .resize(250, 250)
            .centerInside()
            .into(new Target() {
                @Override
                public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                    Marker driver_marker = mMap.addMarker(new MarkerOptions()
                            .position(new LatLng(Double.parseDouble(lat), Double.parseDouble(lng)))
                            .icon(BitmapDescriptorFactory.fromBitmap(bitmap))
                            .title(name)
                            .snippet(address)
                    );


                    @Override
                    public void onBitmapFailed (Drawable errorDrawable){
                    }

                    @Override
                    public void onPrepareLoad (Drawable placeHolderDrawable){
                    }
                });
            }

I added this inside the onBitmapLoaded:

Paint paint = new Paint();
    paint.setColor(Color.YELLOW);
    paint.setStrokeWidth(10);
    paint.setShadowLayer(5, 0, 1, Color.RED);

    Canvas canvas = new Canvas(bitmap);
    canvas.drawLine(0, 0, canvas.getWidth(), 0, paint);
    canvas.drawLine(0, 0, 0, canvas.getHeight(), paint);
    canvas.drawLine(0, canvas.getHeight(), canvas.getWidth(), canvas.getHeight(), paint);
    canvas.drawLine(canvas.getWidth(), 0, canvas.getWidth(), canvas.getHeight(), paint);

And that seems to added the borders, but how do I add that inverted pyramid with the Canvas? Thanks, after that, I'm pretty much done! :D

Bayles answered 4/1, 2016 at 8:1 Comment(6)
it wasn't answered thereBayles
at best, what i can get is i make a canvas from the bitmap, how do i then create the border with the canvas?Bayles
Create your own transform class that draws Paint objects to a Canvas. You could start with this: gist.github.com/aprock/6213395Demetrademetre
Try to set anchor to driver_marker(Marker)driver_marker.anchor(0.5f, 0.5f); see hereHopple
well, i added canvas and Paint which seems to create the borders, now all i need is the inverted pyramid thing with the Canvas. I don't know how, haha.Bayles
I updated the question, so you can see which code i added for the BorderBayles
D
15

Here is a transformation class that I got working. It's lacking the corner radius and any gradients, but it has the inverted pyramid on the bottom, and it should serve as a good starting point.

Here is the transformation class:

import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Shader;

public class BubbleTransformation implements com.squareup.picasso.Transformation {
    private static final int outerMargin = 40;
    private final int margin;  // dp

    // margin is the board in dp
    public BubbleTransformation(final int margin) {
        this.margin = margin;
    }

    @Override
    public Bitmap transform(final Bitmap source) {
        Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        Paint paintBorder = new Paint();
        paintBorder.setColor(Color.CYAN);
        paintBorder.setStrokeWidth(margin);
        canvas.drawRoundRect(new RectF(outerMargin, outerMargin, source.getWidth() - outerMargin, source.getHeight() - outerMargin), 0, 0, paintBorder);

        Paint trianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        trianglePaint.setStrokeWidth(2);
        trianglePaint.setColor(Color.CYAN);
        trianglePaint.setStyle(Paint.Style.FILL_AND_STROKE);
        trianglePaint.setAntiAlias(true);

        Path triangle = new Path();
        triangle.setFillType(Path.FillType.EVEN_ODD);
        triangle.moveTo(outerMargin, source.getHeight() / 2);
        triangle.lineTo(source.getWidth()/2,source.getHeight());
        triangle.lineTo(source.getWidth()-outerMargin,source.getHeight()/2);
        triangle.close();

        canvas.drawPath(triangle, trianglePaint);

        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
        canvas.drawRoundRect(new RectF(margin+outerMargin, margin+outerMargin, source.getWidth() - (margin + outerMargin), source.getHeight() - (margin + outerMargin)), 0, 0, paint);

        if (source != output) {
            source.recycle();
        }

        return output;
    }

    @Override
    public String key() {
        return "rounded";
    }
}

The call to Picasso:

 Picasso.with(getActivity())
            .load(user_photo_url)
            .resize(250,250)
            .centerCrop()
            .transform(new BubbleTransformation(20))
            .into(mTarget);

The Target:

Target mTarget = new Target() {
    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
        Marker driver_marker = mMap.addMarker(new MarkerOptions()
                        .position(latLng)
                        .icon(BitmapDescriptorFactory.fromBitmap(bitmap))
                        .title("test")
                        .snippet("test address")
        );
    }

    @Override
    public void onBitmapFailed(Drawable errorDrawable) {
        Log.d("picasso", "onBitmapFailed");
    }

    @Override
    public void onPrepareLoad(Drawable placeHolderDrawable) {

    }
};

Result:

enter image description here

Demetrademetre answered 4/1, 2016 at 10:48 Comment(4)
Nice answer +1 for that. Tell me one thing, what if I want that marker rounded with small arrow below it?Koph
@ZubairAhmed Have you find a solution for the round marker with a small arrow below it??Chemisorb
@Chemisorb Yes I did by changing in radius i guess but this was very old project I will find out the source and let you knowKoph
@Chemisorb I believe this is what you're looking for: https://mcmap.net/q/138130/-how-to-make-a-google-map-marker-with-a-photo-inside-round-speech-bubbleDemetrademetre
M
2

You can set in kotlin like this..

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)


        mapView.getMapAsync { googleMap ->
            googleMap1 = googleMap as GoogleMap
            addCustomMarker()
        }

    }


 private fun addCustomMarker() {
        Log.d("addCustomMarker", "addCustomMarker()")
        if (googleMap1 == null) {
            return
        }
        // adding a marker on map with image from  drawable
        googleMap1.addMarker(
            MarkerOptions()
                .position(LatLng(23.0225 , 72.5714))
                .icon(BitmapDescriptorFactory.fromBitmap(getMarkerBitmapFromView()))
        )
    }



    private fun getMarkerBitmapFromView(): Bitmap? {
        val customMarkerView: View? = layoutInflater.inflate(R.layout.view_custom_marker, null)
//        val markerImageView: ImageView =
//            customMarkerView.findViewById<View>(R.id.profile_image) as ImageView
        customMarkerView?.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED );
        customMarkerView?.layout(0, 0, customMarkerView.measuredWidth, customMarkerView.measuredHeight);
        customMarkerView?.buildDrawingCache();
        val returnedBitmap = Bitmap.createBitmap(
            customMarkerView!!.measuredWidth, customMarkerView.measuredHeight,
            Bitmap.Config.ARGB_8888
        )
        val canvas = Canvas(returnedBitmap)
        canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC_IN)
        val drawable = customMarkerView.background

        drawable?.draw(canvas);
        customMarkerView.draw(canvas);
        return returnedBitmap;

    }
Malaria answered 12/3, 2020 at 11:57 Comment(0)
T
1

here marker view is your custom marker layout

    val view = LayoutInflater.from(context).inflate(R.layout.marker_view, 
    null,false)

    val bitmap = getBitmapFromView(view)

    // Uses a custom icon.
     mSydney = mMap.addMarker(MarkerOptions()
        .position(SYDNEY)
        .title("Sydney")
        .snippet("Population: 4,627,300")
        .icon(BitmapDescriptorFactory.fromResource(bitmap)))

use this function to convert bitmap from view

private fun getBitmapFromView(view: View): Bitmap {
        view.measure(MeasureSpec.UNSPECIFIED, 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
    }
Troubadour answered 25/5, 2018 at 6:19 Comment(0)
B
0

I am a bit late to the party but all the above solutions are either not working or deprecated.

If you want something similar to the image below then You just have to follow these 3 simple steps.

enter image description here

1. Create your XML layout which you want to be shown as marker

I have created custom_location_marker.xml layout.

2. Just copy and paste this function in your Map Fragment/ Map Activity

    private fun createDrawableFromView(): Bitmap {
    val customMarkerView: View = View.inflate(
        requireActivity(),
        R.layout.custom_location_marker, null
    )

    customMarkerView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
    customMarkerView.layout(
        0,
        0,
        customMarkerView.measuredWidth,
        customMarkerView.measuredHeight
    )

    val bitmap =
        Bitmap.createBitmap(
            customMarkerView.width,
            customMarkerView.height,
            Bitmap.Config.ARGB_8888
        )
    val canvas = Canvas(bitmap)
    customMarkerView.draw(canvas)
    return bitmap
}

3. And then when the map is ready, just call this function to add marker in the map:

googleMap.addMarker(MarkerOptions().position(LatLng(24.0, 260.0)).icon(
        BitmapDescriptorFactory
            .fromBitmap(createDrawableFromView())
    ))
Bruce answered 8/11, 2021 at 12:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.