如何获得一个Drawable,它是另一个Drawable的镜像版本?

时间:2018-01-16 14:11:24

标签: android android-drawable image-rotation

背景

我知道可以创建一个Drawable(或Bitmap)的旋转版本(就此而言here):

@JvmStatic
fun getRotateDrawable(d: Drawable, angle: Int): Drawable {
    if (angle % 360 == 0)
       return d
    return object : LayerDrawable(arrayOf(d)) {
        override fun draw(canvas: Canvas) {
            canvas.save()
            canvas.rotate(angle.toFloat(), (d.bounds.width() / 2).toFloat(), (d.bounds.height() / 2).toFloat())
            super.draw(canvas)
            canvas.restore()
        }
    }
}

问题

我想将autoMirrored设置为某个drawable(在我的情况下是VectorDrawable),它会翻转(镜像使左边是右边,右边是左边,但不影响顶部和底部)以防万一设备的语言环境是RTL。

作为一个例子(这只是一个例子!),如果你拿一个显示左箭头的drawable,翻转后它将是一个右箭头。

可悲的是,这只能从API 19获得。

这就是为什么我决定用它制作一个新的Drawable,成为原版的翻版版本

我尝试了什么

我发现了一篇很好的文章,使用矩阵对View here做同样的事情。所以我试过这个:

    @JvmStatic
    fun getMirroredDrawable(d: Drawable): Drawable {
        return object : LayerDrawable(arrayOf(d)) {
            override fun draw(canvas: Canvas) {
                canvas.save()
                val matrix = Matrix()
                // use this for the other flipping: matrix.preScale(1.0f, -1.0f)
                matrix.preScale(-1.0f, 1.0f);
                canvas.matrix = matrix
                super.draw(canvas)
                canvas.restore()
            }
        }
    }
可悲的是,出于某种原因,这使得抽签根本没有显示出来。也许它确实有效,但试图从显示它的任何View的界限中显示出来。

问题

如何制作给定Drawable的翻转版本,类似于我为旋转Drawable所做的操作?

解决方案:

根据下面建议的答案(here),这是一个很好的方法:

fun Drawable.getMirroredDrawable(): Drawable {
    return object : LayerDrawable(arrayOf(this)) {
        val drawingRect = Rect()
        val matrix = Matrix()
        override fun draw(canvas: Canvas) {
            matrix.reset()
            matrix.preScale(-1.0f, 1.0f, canvas.width / 2.0f, canvas.height / 2.0f)
            canvas.matrix = matrix
            drawingRect.left = (canvas.width - intrinsicWidth) / 2
            drawingRect.top = (canvas.height - intrinsicHeight) / 2
            drawingRect.right = drawingRect.left + intrinsicWidth
            drawingRect.bottom = drawingRect.top + intrinsicHeight
            if (bounds != drawingRect)
                bounds = drawingRect
            super.draw(canvas)
        }
    }
}

3 个答案:

答案 0 :(得分:3)

指定翻转操作的中心。

matrix.preScale(-1.0f, 1.0f, canvas.getWidth() / 2, canvas.getHeight() / 2);

这是一个自定义Drawable类,可用于镜像drawable:

public class MirroredDrawable extends Drawable {
    final Drawable mDrawable;
    final Matrix matrix = new Matrix();

    MirroredDrawable(Drawable drawable) {
        mDrawable = drawable;
    }

    @Override
    public void draw(@NonNull Canvas canvas) {
        matrix.reset();
        matrix.preScale(-1.0f, 1.0f, canvas.getWidth() / 2, canvas.getHeight() / 2);
        canvas.setMatrix(matrix);

        Rect drawingRect = new Rect();
        drawingRect.left = (canvas.getWidth() - mDrawable.getIntrinsicWidth()) / 2;
        drawingRect.top = (canvas.getHeight() - mDrawable.getIntrinsicHeight()) / 2;
        drawingRect.right = drawingRect.left + mDrawable.getIntrinsicWidth();
        drawingRect.bottom = drawingRect.top + mDrawable.getIntrinsicHeight();
        mDrawable.setBounds(drawingRect);
        mDrawable.draw(canvas);
    }

    // Other methods required to extend Drawable but aren't used here.

    @Override
    public void setAlpha(int alpha) { }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) { }

    @Override
    public int getOpacity() { return PixelFormat.OPAQUE; }
}

以下是它的应用方式:

    Drawable drawable = getResources().getDrawable(R.drawable.your_drawable);
    getSupportActionBar().setHomeAsUpIndicator(new MirroredDrawable(drawable));

答案 1 :(得分:1)

您可以在视图的xml中使用android:scaleX="-1"来显示可绘制的镜像。要使其根据布局的方向自动运行,您可以使用整数资源值:

<ImageView
    android:scaleX="@integer/rtl_flip_factor"
    android:src="@android:drawable/ic_media_play"/>

要完成此操作,您需要使用普通values/integers.xml作为默认(LTR)案例

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="rtl_flip_factor">1</integer>
</resources>

和RTL案例的另一个values-ldrtl/integers.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="rtl_flip_factor">-1</integer>
</resources>

答案 2 :(得分:0)

您可以使用群组标记来实现相同目标。

以下是一个例子:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportHeight="24.0"
    android:viewportWidth="24.0">
    <group
        android:name="rotationGroup"
        android:rotation="@dimen/rotation_degree">
        <path .... />
    </group>
</vector>

现在在普通值文件夹和ldrtl文件夹中定义不同的rotation_degree篇。

在值文件夹下

<item name="rotation_degree" format="float" type="dimen">0.0</item>

在values-ldrtl下

<item name="rotation_degree" format="float" type="dimen">180.0</item>