With the support library now fully supporting vector images, I'm trying to switch to vector images as much as I can in my app. An issue I'm running into is that it seems impossible to repeat them.
With bitmap images the following xml could be used:
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/repeat_me"
android:tileMode="repeat"
/>
This does not work, as vector images can not be used in bitmaps: https://code.google.com/p/android/issues/detail?id=187566
Is there any other way to tile/repeat vector images?
This is the java version of Nick Butcher solution:
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
public class TileDrawable extends Drawable {
private final Paint paint;
public TileDrawable(Drawable drawable, Shader.TileMode tileMode) {
paint = new Paint();
paint.setShader(new BitmapShader(getBitmap(drawable), tileMode, tileMode));
}
@Override
public void draw(@NonNull Canvas canvas) {
canvas.drawPaint(paint);
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
paint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
private Bitmap getBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable)
return ((BitmapDrawable) drawable).getBitmap();
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
}
}
You can use this drawable class in code with vector patterns:
view.setBackground(new TileDrawable(getContext().getDrawable(R.drawable.pattern), Shader.TileMode.REPEAT));
Thanks to @pskink I made a drawable that tiles another drawable: https://gist.github.com/9ffbdf01478e36194f8f
This has to be set in code, it can not be used from XML:
public class TilingDrawable extends android.support.v7.graphics.drawable.DrawableWrapper {
private boolean callbackEnabled = true;
public TilingDrawable(Drawable drawable) {
super(drawable);
}
@Override
public void draw(Canvas canvas) {
callbackEnabled = false;
Rect bounds = getBounds();
Drawable wrappedDrawable = getWrappedDrawable();
int width = wrappedDrawable.getIntrinsicWidth();
int height = wrappedDrawable.getIntrinsicHeight();
for (int x = bounds.left; x < bounds.right + width - 1; x+= width) {
for (int y = bounds.top; y < bounds.bottom + height - 1; y += height) {
wrappedDrawable.setBounds(x, y, x + width, y + height);
wrappedDrawable.draw(canvas);
}
}
callbackEnabled = true;
}
@Override
protected void onBoundsChange(Rect bounds) {
}
/**
* {@inheritDoc}
*/
public void invalidateDrawable(Drawable who) {
if (callbackEnabled) {
super.invalidateDrawable(who);
}
}
/**
* {@inheritDoc}
*/
public void scheduleDrawable(Drawable who, Runnable what, long when) {
if (callbackEnabled) {
super.scheduleDrawable(who, what, when);
}
}
/**
* {@inheritDoc}
*/
public void unscheduleDrawable(Drawable who, Runnable what) {
if (callbackEnabled) {
super.unscheduleDrawable(who, what);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With