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.

Shuddh
quelle
@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

SidMorad
quelle
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)
        }
    }
Leo Droidcoder
quelle
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

prerak
quelle
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)
}
Kasun Thilina
quelle
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;
    }
Shahab Saalami
quelle
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

M. Yogeshwaran
quelle
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:

Shihab Uddin
quelle
-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>
Eswar
quelle
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;

    }




}
Kush
quelle