现在支持库完全支持矢量图像,我正试图在我的应用程序中尽可能多地切换到矢量图像。 我遇到的一个问题是,似乎无法重复它们。
使用位图图像可以使用以下xml:
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/repeat_me"
android:tileMode="repeat"
/>
这不起作用,因为矢量图像不能用于位图: https://code.google.com/p/android/issues/detail?id=187566
有没有其他方法来平铺/重复矢量图像?
答案 0 :(得分:6)
感谢@pskink我制作了一个可绘制的另一个drawable: https://gist.github.com/9ffbdf01478e36194f8f
这必须在代码中设置,不能在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);
}
}
}
答案 1 :(得分:3)
这是Nick Butcher解决方案的Java版本:
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;
}
}
您可以在具有矢量模式的代码中使用此drawable类:
view.setBackground(new TileDrawable(getContext().getDrawable(R.drawable.pattern), Shader.TileMode.REPEAT));
答案 2 :(得分:1)
我想根据其中一个答案(here)中的建议,提出一个完整的解决方案,不需要支持库隐藏类,用Kotlin编写:
<强> DrawableWrapper.kt 强>
<select [(ngModel)]="usuario.pais" name="s" class="form-control">
<option value="">Select a Country</option><!--My PlaceHolder-->
<option *ngFor="let pais of paises" value="pais.codigo">{{pais.nombre}}</option>
</select>
<强> TilingDrawable.kt 强>
open class DrawableWrapper(drawable: Drawable) : Drawable(), Drawable.Callback {
var wrappedDrawable: Drawable = drawable
set(drawable) {
field.callback = null
field = drawable
drawable.callback = this
}
override fun draw(canvas: Canvas) = wrappedDrawable.draw(canvas)
override fun onBoundsChange(bounds: Rect) {
wrappedDrawable.bounds = bounds
}
override fun setChangingConfigurations(configs: Int) {
wrappedDrawable.changingConfigurations = configs
}
override fun getChangingConfigurations() = wrappedDrawable.changingConfigurations
override fun setDither(dither: Boolean) = wrappedDrawable.setDither(dither)
override fun setFilterBitmap(filter: Boolean) {
wrappedDrawable.isFilterBitmap = filter
}
override fun setAlpha(alpha: Int) {
wrappedDrawable.alpha = alpha
}
override fun setColorFilter(cf: ColorFilter?) {
wrappedDrawable.colorFilter = cf
}
override fun isStateful() = wrappedDrawable.isStateful
override fun setState(stateSet: IntArray) = wrappedDrawable.setState(stateSet)
override fun getState() = wrappedDrawable.state
override fun jumpToCurrentState() = DrawableCompat.jumpToCurrentState(wrappedDrawable)
override fun getCurrent() = wrappedDrawable.current
override fun setVisible(visible: Boolean, restart: Boolean) = super.setVisible(visible, restart) || wrappedDrawable.setVisible(visible, restart)
override fun getOpacity() = wrappedDrawable.opacity
override fun getTransparentRegion() = wrappedDrawable.transparentRegion
override fun getIntrinsicWidth() = wrappedDrawable.intrinsicWidth
override fun getIntrinsicHeight() = wrappedDrawable.intrinsicHeight
override fun getMinimumWidth() = wrappedDrawable.minimumWidth
override fun getMinimumHeight() = wrappedDrawable.minimumHeight
override fun getPadding(padding: Rect) = wrappedDrawable.getPadding(padding)
override fun invalidateDrawable(who: Drawable) = invalidateSelf()
override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long) = scheduleSelf(what, `when`)
override fun unscheduleDrawable(who: Drawable, what: Runnable) = unscheduleSelf(what)
override fun onLevelChange(level: Int) = wrappedDrawable.setLevel(level)
override fun setAutoMirrored(mirrored: Boolean) = DrawableCompat.setAutoMirrored(wrappedDrawable, mirrored)
override fun isAutoMirrored() = DrawableCompat.isAutoMirrored(wrappedDrawable)
override fun setTint(tint: Int) = DrawableCompat.setTint(wrappedDrawable, tint)
override fun setTintList(tint: ColorStateList?) = DrawableCompat.setTintList(wrappedDrawable, tint)
override fun setTintMode(tintMode: PorterDuff.Mode) = DrawableCompat.setTintMode(wrappedDrawable, tintMode)
override fun setHotspot(x: Float, y: Float) = DrawableCompat.setHotspot(wrappedDrawable, x, y)
override fun setHotspotBounds(left: Int, top: Int, right: Int, bottom: Int) = DrawableCompat.setHotspotBounds(wrappedDrawable, left, top, right, bottom)
}
样本用法:
class TilingDrawable(drawable: Drawable) : DrawableWrapper(drawable) {
private var callbackEnabled = true
override fun draw(canvas: Canvas) {
callbackEnabled = false
val bounds = bounds
val width = wrappedDrawable.intrinsicWidth
val height = wrappedDrawable.intrinsicHeight
var x = bounds.left
while (x < bounds.right + width - 1) {
var y = bounds.top
while (y < bounds.bottom + height - 1) {
wrappedDrawable.setBounds(x, y, x + width, y + height)
wrappedDrawable.draw(canvas)
y += height
}
x += width
}
callbackEnabled = true
}
override fun onBoundsChange(bounds: Rect) {}
override fun invalidateDrawable(who: Drawable) {
if (callbackEnabled)
super.invalidateDrawable(who)
}
override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long) {
if (callbackEnabled)
super.scheduleDrawable(who, what, `when`)
}
override fun unscheduleDrawable(who: Drawable, what: Runnable) {
if (callbackEnabled)
super.unscheduleDrawable(who, what)
}
}
答案 3 :(得分:1)
检查Nick Butcher解决方案:
https://gist.github.com/nickbutcher/4179642450db266f0a33837f2622ace3
将TileDrawable类添加到项目中,然后将tile drawable设置为图像视图:
// after view created
val d = ContextCompat.getDrawable(this, R.drawable.pattern)
imageView.setImageDrawable(TileDrawable(d, Shader.TileMode.REPEAT))
答案 4 :(得分:0)
我看到了两个解决此问题的简单方法:
1。。要在SVG操作软件(如“ Inkscape”或“ CorelDraw”)中创建(重复)图案。然后在“ ImageView”中使用此“ created_manually_pattern_svg”作为
...
app:srcCompat="@drawable/created_manually_pattern_svg"
...
甚至
...
android:background="@drawable/created_manually_pattern_svg"
...
在任何其他“视图”中显示(但我不确定它是否适用于所有API级别)
2。。将“ .svg”文件导出为“ .png”,然后使用“位图”。