I'm trying to add support to tablets in my app and run into IllegalArgumentException thrown by this line of code:
marker.setIcon(BitmapDescriptorFactory.fromResource(R.drawable.arrow_green_10by19))
The method .fromResource works fine with the R.drawable.arrow_green_10by19 from an image file (png) but when the png is replaced with the vector file arrow_green_10by19.xml (which renders fine in the Android Studio IDE) it generates a runtime as mentioned.
Does anybody knows how to implement a vector resource in the BitmapDescriptorFactory and could help me out?
Thanks.
I had the same problem but I realized that on my device with API 16 it works fine but with API 21 it crashes. Finally it works in both devices using this solution. Here the code:
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static Bitmap getBitmap(VectorDrawable vectorDrawable) {
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());
vectorDrawable.draw(canvas);
return bitmap;
}
and this:
private static 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");
}
}
So I combined those 2 functions in this way:
private Marker addMark(LatLng latLng, String title) {
Bitmap bitmap = getBitmap(getContext(), R.drawable.ic_place_24dp);
Marker marker = googleMap.addMarker(new MarkerOptions().position(latLng)
.title(title)
.icon(BitmapDescriptorFactory.fromBitmap(bitmap))
.draggable(true));
return marker;
}
Where R.drawable.ic_place_24dp is a vector asset (.xml), not a .png
Related
I am reading this blog post about VectorDrawable. It is mentioned that one of the trade-offs of using vector images is that it is more expensive to render. The blog also states:
For static vectors, the drawing stage only needs to be performed once and can then be cached to a Bitmap.
But the blog did not explain how to do the caching. How to do it?
Here are some ways to do it:
public static Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
// depending on the support lib version you may have to use
// 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;
}
With Android KTX
val bitmap = AppCompatResources.getDrawable(context, drawableId).toBitmap()
Hope it helps
I want to use animatedVectorDrawable as the map marker in Android. Is there a way to do this.
What i tried is, I use BitmapDescriptorFactory class to convert VectorDrawable to bitmap and it work fine , but when i go to convert AnimatedVectorDrawable it show nothing on map
Below code what i tried so far
.
.
.
MarkerOptions marker1 = new MarkerOptions();
marker1.icon( getBitmapDescriptor(R.drawable.setpickuplocationdrawable));
marker1.position(pickuplatlng);
marker1.title("Marker at place1");
googleMap.addMarker(marker1);
}
private BitmapDescriptor getBitmapDescriptor(int id) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AnimatedVectorDrawable vectorDrawable = (AnimatedVectorDrawable) getDrawable(id);
int h = vectorDrawable.getIntrinsicHeight();
int w = vectorDrawable.getIntrinsicWidth();
vectorDrawable.setBounds(0, 0, w, h);
Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bm);
vectorDrawable.draw(canvas);
return BitmapDescriptorFactory.fromBitmap(bm);
} else {
return BitmapDescriptorFactory.fromResource(id);
}
}
You cannot do that. In order to add an image to map as marker, you will need a bitmap (png preferable).
What you can do is convert the vector to a bitmap and try again.
BitmapDescriptor bmpD = BitmapDescriptorFactory.fromResource(R.raw.podval);
Log.d("myLog", ":" + bmpD);
GroundOverlayOptions newarkMap = new GroundOverlayOptions()
.image(bmpD)
.position(sydney, 8600f, 6500f);
Log.d("myLog", ":" + newarkMap);
GroundOverlay imageOverlay = mMap.addGroundOverlay(newarkMap);
Failed to decode image. The provided image must be a Bitmap.
But in log I got :com.google.android.gms.maps.model.BitmapDescriptor#58e0ee6
:com.google.android.gms.maps.model.GroundOverlayOptions#1ea9c27
Also I converted jpg image to bmp, after failing to convert it here
Help please.
See https://stackoverflow.com/a/45564994/2914140 for vector drawables (SVG).
private BitmapDescriptor bitmapDescriptorFromVector(Context context, #DrawableRes 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);
}
Place your image in the drawable folder, not in the raw folder. Also make sure the resource is a valid image file.
I need to change the default cross-icon in ChromeCustomTab Android, I am changing it with back-icon using the code below:
Bitmap icon = BitmapFactory.decodeResource(context.getResources(),R.drawable.ic_arrow_back_white_24dp);
It is working fine with PNGs but not with SVGs.
As per this documentation, we have to maintain size of image according to this documentation.
https://developer.android.com/reference/android/support/customtabs/CustomTabsIntent.html#KEY_ICON
I think it is not working because they are not following the dimensions given in Documentation.
You need to return a valid Bitmap. For a VectorDrawable it is necessary to do something more. You can use these methods:
private static Bitmap bitmapFromDrawable(Context context, int drawableId) {
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
if (drawable instanceof VectorDrawable) {
return bitmapFromVectorDrawable((VectorDrawable) drawable);
}
return ((BitmapDrawable) drawable).getBitmap();
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static Bitmap bitmapFromVectorDrawable(VectorDrawable vectorDrawable) {
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());
vectorDrawable.draw(canvas);
return bitmap;
}
Then you can use it like:
builder.setCloseButtonIcon(bitmapFromDrawable(this, R.drawable. ic_arrow_back_white_24dp));
I have a png image inside my Drawable folder. The same image I use it in many markers but in different sizes. Instead of creating many images with different sizes, I wanted to create XMLs inside the Drawable folder reusing the orignial image.
I tried solutions on this answers: Scale a drawable resource in XML (Android) but they are not working in my cases. When I reach
BitmapDescriptor scaledIcon = BitmapDescriptorFactory.fromResource(R.drawable.scaled_marker_image); //scaled_marker_image is the XML that resize the original image
mMap.addMarker(new MarkerOptions().position(new LatLng(location.getLatitude(), location.getLongitude())).title("Marker").icon(scaledIcon));
Basically in the MarjerOptions().icon(scaledIcon) I get nullPointerException
Any ideas how to achieve this?
XML would look like this (as shown in Scale a drawable resource in XML (Android) answer)
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="#drawable/marker_image"
android:insetTop="30dp"
android:insetLeft="10dp"
android:insetRight="10dp"
android:insetBottom="0dp"
/>
We define a method to transform a Drawable to Bitmap
public static Bitmap drawableToBitmap (Drawable drawable) {
Bitmap bitmap = null;
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if(bitmapDrawable.getBitmap() != null) {
return bitmapDrawable.getBitmap();
}
}
if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
} else {
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;
}
And then, to set the drawable to the marker:
Drawable drawable = getResources().getDrawable(getResources().getDrawable(R.drawable.mi_posicion_marker2));
BitmapDescriptor scaledIcon = BitmapDescriptorFactory.fromBitmap(drawableToBitmap(drawable));
mMap.addMarker(new MarkerOptions().position(new LatLng(location.getLatitude(), location.getLongitude())).title("Marker").icon(scaledIcon));