Benutzerdefinierte Markierung in Google Maps in Android mit Vektor-Asset-Symbol


73

Wie können wir ein Kartenmarkierungssymbol mit einer Vektor-Asset- Datei erreichen, wie Google es programmgesteuert so zeigt:

Karte

Aktualisieren:

map.addMarker(new MarkerOptions()
    .position(latLng)
    .icon(BitmapDescriptorFactory.fromResource(R.drawable.your_vector_asset))
    .title(title);

Dies funktioniert nicht, wenn es sich um Vektor-Assets handelt. Der Hauptgrund, die Frage zu stellen. Der Fehler mit dem obigen Code:

java.lang.IllegalArgumentException: Bild konnte nicht dekodiert werden. Das bereitgestellte Bild muss eine Bitmap sein.


@RishabhMahatha Ich kann es leicht mit PNG machen, aber das Problem ist, dass PNG eine schwere Datei ist. entweder muss ich es in meiner apk speichern oder vom server aufrufen. Aber ich brauche es speziell aus der Vektor-Asset-Datei.
Shuddh

@LucaNicoletti Ich muss dies mithilfe einer Vector Asset (oder SVG) -Datei erreichen. und ich bekomme keine Bibliothek oder Methode, um es zu tun.
Shuddh

jemand? noch etwas gefunden ..
Shuddh

1
Es kann auch in dieser Antwort gefunden werden: stackoverflow.com/questions/33696488/…
Erfan

Antworten:


37

Ich suchte nach genau der gleichen Anforderung und als ich diese Frage sah, war ich zuerst glücklich, aber genau wie bei @Shuddh war ich mit den gegebenen Antworten nicht zufrieden.

Um meine Geschichte kurz zu machen, verwende ich folgenden Code für diese Anforderung:

private BitmapDescriptor bitmapDescriptorFromVector(Context context, @DrawableRes  int vectorDrawableResourceId) {
    Drawable background = ContextCompat.getDrawable(context, R.drawable.ic_map_pin_filled_blue_48dp);
    background.setBounds(0, 0, background.getIntrinsicWidth(), background.getIntrinsicHeight());
    Drawable vectorDrawable = ContextCompat.getDrawable(context, vectorDrawableResourceId);
    vectorDrawable.setBounds(40, 20, vectorDrawable.getIntrinsicWidth() + 40, vectorDrawable.getIntrinsicHeight() + 20);
    Bitmap bitmap = Bitmap.createBitmap(background.getIntrinsicWidth(), background.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    background.draw(canvas);
    vectorDrawable.draw(canvas);
    return BitmapDescriptorFactory.fromBitmap(bitmap);
}

und ein Anwendungsbeispiel:

.icon(bitmapDescriptorFromVector(this, R.drawable.ic_car_white_24dp));

Hinweis: Möglicherweise möchten Sie für Ihre Vektoren eine andere Begrenzung verwenden. Meine Vektoren hatten eine Größe von 24 dp und ich habe ein 48 dp-PNG-Bild (blauer Teil, der auch ein Vektor sein kann) als Hintergrund verwendet.

UPDATE: Hinzufügen eines Screenshots nach Anforderung.

Screenshot für das Endergebnis


Ich denke, das wird den Trick machen. Ich werde dies überprüfen und die Antwort markieren. Aber wenn Sie einen Screenshot haben. Bitte teilen.
Shuddh

Ich habe einen Screenshot hinzugefügt, ich hoffe, das klärt, was ursprünglich die Anforderung war! ;-) "Ich meine, Vektoren in einem Map-Pin wiederzuverwenden"
SidMorad

2
Ich denke, dass die Berechnungen für die inneren Bildgrenzen unterschiedlich sein sollten (Kotlin-Implementierung unten): val left = (background.intrinsicWidth - vectorDrawable.intrinsicWidth) / 2 val top = (background.intrinsicHeight - vectorDrawable.intrinsicHeight) / 3 vectorDrawable.setBounds(left, top, left + vectorDrawable.intrinsicWidth, top + vectorDrawable.intrinsicHeight)
gswierczynski

Sie sehen wirklich niedrig aufgelöst aus
xjcl

@xjcl Ich habe gedacht, jemand wird das sagen! :) und deshalb füge ich diesen Teil meiner Antwort hinzu: "Ich habe ein 48dp-PNG-Bild (blauer Teil, der auch ein Vektor sein kann ) als Hintergrund verwendet"
SidMorad

111

Sie können diese Methode verwenden:

private BitmapDescriptor bitmapDescriptorFromVector(Context context, int vectorResId) {
        Drawable vectorDrawable = ContextCompat.getDrawable(context, vectorResId);
        vectorDrawable.setBounds(0, 0, vectorDrawable.getIntrinsicWidth(), vectorDrawable.getIntrinsicHeight());
        Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(), vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        vectorDrawable.draw(canvas);
        return BitmapDescriptorFactory.fromBitmap(bitmap);
}

Ihr Code sieht also folgendermaßen aus:

map.addMarker(new MarkerOptions()
                .position(latLng)
                .icon(bitmapDescriptorFromVector(getActivity(), R.drawable.your_vector_asset))
                .title(title);

Edit :
In Kotlin sieht es vielleicht so aus:

private fun bitmapDescriptorFromVector(context: Context, vectorResId: Int): BitmapDescriptor? {
        return ContextCompat.getDrawable(context, vectorResId)?.run {
            setBounds(0, 0, intrinsicWidth, intrinsicHeight)
            val bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888)
            draw(Canvas(bitmap))
            BitmapDescriptorFactory.fromBitmap(bitmap)
        }
    }

1
Hast du es versucht. Ich habe diesen Code schon eine Weile nicht mehr gesehen!
Shuddh

Klar, ich habe es in meinem Projekt verwendet
Leo Droidcoder

Dies löst immer noch mein Problem! Was Ihre Methode mir gibt, ist nur das Autosymbol und nicht der blaue Hintergrund. Ich muss diesen Hintergrund und über diesem Drar dieses Symbol behalten.
Shuddh

Meinen Sie damit, dass das Autosymbol ein vom Pin getrenntes Symbol ist?
Leo Droidcoder

2
Verwendet dies in meinem Projekt, um einen Marker vom Vektor-Asset zu erhalten.
anoo_radha

5

Es könnte etwas spät sein, aber dies funktioniert hervorragend mit Google Maps v2:

public static BitmapDescriptor getBitmapFromVector(@NonNull Context context,
                                                   @DrawableRes int vectorResourceId,
                                                   @ColorInt int tintColor) {

    Drawable vectorDrawable = ResourcesCompat.getDrawable(
            context.getResources(), vectorResourceId, null);
    if (vectorDrawable == null) {
        Log.e(TAG, "Requested vector resource was not found");
        return BitmapDescriptorFactory.defaultMarker();
    }
    Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
            vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    DrawableCompat.setTint(vectorDrawable, tintColor);
    vectorDrawable.draw(canvas);
    return BitmapDescriptorFactory.fromBitmap(bitmap);
}

Initialisiert als:

locationMarkerIcon = LayoutUtils.getBitmapFromVector(ctx, R.drawable.ic_location_marker,
                ContextCompat.getColor(ctx, R.color.marker_color));

Verwendung:

googleMap.addMarker(MarkerOptions().icon(getMarkerIcon()).position(latLng));

Hinweis: getMarkerIcon()Gibt nur die initialisierte Nicht-Null- locationMarkerIconMitgliedsvariable zurück.

Bildschirmfoto:

Geben Sie hier die Bildbeschreibung ein


1
Es ist nicht das, wonach die Frage fragt. Wenn Sie den Screenshot bei der richtigen Antwort sehen können.
Shuddh

1
@Shuddh Grundsätzlich ist mein Vektor-Asset in meinem Screenshot etwas anders (basierend auf meinem Projekt), aber soweit ich das sehe, wurde in Ihrer ursprünglichen Frage gefragt, wie ein Vektor-Asset als Markierungssymbol verwendet werden soll, und genau das macht die statische Methode (zusammen) mit auch dynamisches Hinzufügen einer Farbe).
Prerak

Es fügt keine Farbe dynamisch hinzu. Es ist im Grunde die Änderung im inneren Symbol. Wenn Sie den Screenshot in der ausgewählten Antwort sehen können
Shuddh

Supperb! In meinem Fall habe ich die Tönungsfarbe losgeworden und es funktioniert! Außerdem würde ich vorschlagen, den Anker des Markers wie folgt zu ändern (wenn es sich um einen klassischen Stift handelt):.anchor(0.5f, 1f);
russellhoff

5

Hier ist der Code für Kotlin-Liebhaber;)

private fun bitMapFromVector(vectorResID:Int):BitmapDescriptor {
    val vectorDrawable=ContextCompat.getDrawable(context!!,vectorResID)
    vectorDrawable!!.setBounds(0,0,vectorDrawable!!.intrinsicWidth,vectorDrawable.intrinsicHeight)
    val bitmap=Bitmap.createBitmap(vectorDrawable.intrinsicWidth,vectorDrawable.intrinsicHeight,Bitmap.Config.ARGB_8888)
    val canvas=Canvas(bitmap)
    vectorDrawable.draw(canvas)
    return BitmapDescriptorFactory.fromBitmap(bitmap)
}

2
Haben Sie Probleme mit diesem Snippet gehabt? Speziell das setBoundsTeil?
Ravi

2

Vektorressource in Bitmap-Objekt konvertieren und verwenden BitmapDescriptorFactory.fromBitmap(bitmap)

   Bitmap bitmap = getBitmapFromVectorDrawable(getContext(),R.drawable.ic_pin);
   BitmapDescriptor descriptor =BitmapDescriptorFactory.fromBitmap(bitmap);
   MarkerOptions markerOptions = new MarkerOptions();
   markerOptions.icon(descriptor);

Bitmap-Konverter:

 public static Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
        Drawable drawable =  AppCompatResources.getDrawable(context, drawableId)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            drawable = (DrawableCompat.wrap(drawable)).mutate();
        }

        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
                drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);

        return bitmap;
    }

1
Ja, ich habe nach dieser Antwort gesucht, die im Bitmap-Format zurückgegeben wird. :)
Ramkesh Yadav

1

Wenn jemand, der in Kotlin sucht, hier die Methode für Sie ist:

  private fun  bitmapDescriptorFromVector(context: Context, vectorResId:Int):BitmapDescriptor {
            var vectorDrawable = ContextCompat.getDrawable(context, vectorResId);
            vectorDrawable!!.setBounds(0, 0, vectorDrawable.getIntrinsicWidth(), vectorDrawable.getIntrinsicHeight());
            var bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(), vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            var canvas =  Canvas(bitmap);
            vectorDrawable.draw(canvas);
            return BitmapDescriptorFactory.fromBitmap(bitmap);
}

Die obige Methode konvertiert Ihr Vektorsymbol in Bitmapdescritor

map.addMarker(new MarkerOptions()
                .position(latLng)
                .icon(bitmapDescriptorFromVector(getActivity(), R.drawable.your_vector_asset))
                .title(title)

und dieser für das Setzen von Markierungen für Ihre Karte, danke für Leo Droidcoder von seiner Antwort, nur ich habe ihn in Kotlin konvertiert


0

In Kotlin: Ich habe den folgenden Code verwendet, um das SVG-Bild auf Marker anzuzeigen. Hier habe ich keine Hintergrundfarbe / SVG verwendet.

fun getBitmapDescriptorFromVector(context: Context, @DrawableRes vectorDrawableResourceId: Int): BitmapDescriptor? {

    val vectorDrawable = ContextCompat.getDrawable(context, vectorDrawableResourceId)
    val bitmap = Bitmap.createBitmap(vectorDrawable!!.intrinsicWidth, vectorDrawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    vectorDrawable.setBounds(0, 0, canvas.width, canvas.height)
    vectorDrawable.draw(canvas)

    return BitmapDescriptorFactory.fromBitmap(bitmap)
}

Verwenden Sie wie folgt:

googleMap?.addMarker(MarkerOptions().position(LatLng(it.latitude!!, it.longitude!!))
            .title(it.airLineDetails))?.setIcon(
            getBitmapDescriptorFromVector(requireContext(), R.drawable.ic_flight_blue))

Bildschirmfoto:


-1

Versuche dies

MarkerOptions op = new MarkerOptions();
op.position(src_latlng);
Marker origin_marker = googleMap.addMarker(op);

Bitmap bitmap = getBitmap(this,R.drawable.ic_map_marker);
origin_marker.setIcon(BitmapDescriptorFactory.fromBitmap(bitmap));

getBitmap

public Bitmap getBitmap(Context context, int drawableId) {
   Drawable drawable = ContextCompat.getDrawable(context, drawableId);
   if (drawable instanceof BitmapDrawable) {
       return BitmapFactory.decodeResource(context.getResources(), drawableId);
   } else if (drawable instanceof VectorDrawable) {
       return getBitmap((VectorDrawable) drawable);
   } else {
       throw new IllegalArgumentException("unsupported drawable type");
   }
}

ic_map_marker.xml

<vector android:height="32dp" android:viewportHeight="512.0"
    android:viewportWidth="512.0" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#f32f00" android:pathData="M288,284.8V480l-64,32V284.8c10.3,2.1 21,3.3 32,3.3S277.7,286.9 288,284.8zM384,128c0,70.7 -57.3,128 -128,128c-70.7,0 -128,-57.3 -128,-128S185.3,0 256,0C326.7,0 384,57.3 384,128zM256,64c0,-17.7 -14.3,-32 -32,-32s-32,14.3 -32,32s14.3,32 32,32S256,81.7 256,64z"/>
</vector>

Können Sie die vectorDrawable-return-Anweisung erklären? Welche getBitmap-Methode verwenden Sie?
Shuddh

Außerdem glaube ich nicht, dass ich dadurch auch den gewünschten Marker bekomme. Die im Bild gezeigte Markierung ist eine Standardmarkierung, die ein Vektorelement enthält. Dieser Code generiert jedoch ein Symbol gemäß dem Vektor-Asset, jedoch nicht innerhalb der Markierung (dem blauen Teil).
Shuddh

@Shuddh Das gesuchte Symbol muss benutzerdefiniert sein. Das Vektor-Asset sollte das blaue und das weiße Autoteil definieren. Und dann fügen Sie diesen Vektor als Symbol hinzu.
Pradumn Kumar Mahanta

@PradumnKumarMahanta Also muss ich einen anderen Vektor für den Hintergrund des Symbols erstellen. Richtig? Aber wie setzt man trotzdem einen Vektor als Marker?
Shuddh

@Shuddh Nein, Sie können einen Vektor für die gesamte Sache erstellen. Marker + Bild. Und fügen Sie diesen Vektor als Marker mit der von Eswar oder Hiristo Stoyanov und mir angegebenen Methode hinzu. Beide arbeiten für mich.
Pradumn Kumar Mahanta

-1

Für einen Kotlin-Benutzer. Bitte überprüfen Sie den folgenden Code. Wie ich es in der Fragment-Klasse getan habe.

class MapPinFragment : Fragment() {

    private lateinit var googleMap1: GoogleMap

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_map_pin, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        mapView.onCreate(savedInstanceState)
        mapView.onResume()

    }

    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()))
        )
    }

    override fun onDestroy() {
        super.onDestroy()
        if (mapView != null)
            mapView.onDestroy()
    }
    override fun onLowMemory() {
        super.onLowMemory()
        mapView.onLowMemory()
    }

    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;

    }




}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.