Android Compose - 如何平铺/重复位图/矢量?

问题描述 投票:0回答:3

Android Compose 平铺图像以用小图案填充背景的方法是什么?

不旋转位图的简单方法可能是这样的:

@Composable
fun TileImage() {
    val pattern = ImageBitmap.imageResource(R.drawable.pattern_bitmap)

    Canvas(modifier = Modifier.fillMaxSize()) {
//    rotate(degrees = -15f) { // The rotation does not produce the desired effect
        val totalWidth = size.width / pattern.width
        val totalHeight = size.height / pattern.height

        var x = 0f
        var y = 0f
        for (i in 0..totalHeight.toInt()) {
            y = (i * pattern.height).toFloat()
            for (j in 0..totalWidth.toInt()) {
                x = (j * pattern.width).toFloat()

                drawImage(
                    pattern,
                    colorFilter = giftColorFilter,
                    topLeft = Offset(x, y)
                )
            }
        }
//    }
    }
}

在 Android XML 中,您可以轻松创建 XML 来重复位图

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/pattern_bitmap" 
android:tileMode="repeat" />

或者,如果您需要平铺矢量,您可以使用自定义 Drawable 类来实现您的目标

TileDrawable(AppCompatResources.getDrawable(context, R.drawable.pattern_vector), Shader.TileMode.REPEAT)

class TileDrawable(drawable: Drawable, tileMode: Shader.TileMode, private val angle: Float? = null) : Drawable() {

    private val paint: Paint = Paint().apply {
        shader = BitmapShader(getBitmap(drawable), tileMode, tileMode)
    }

    override fun draw(canvas: Canvas) {
        angle?.let {
            canvas.rotate(it)
        }
        canvas.drawPaint(paint)
    }

    override fun setAlpha(alpha: Int) {
        paint.alpha = alpha
    }

    override fun getOpacity() = PixelFormat.TRANSLUCENT

    override fun setColorFilter(colorFilter: ColorFilter?) {
        paint.colorFilter = colorFilter
    }

    private fun getBitmap(drawable: Drawable): Bitmap {
        if (drawable is BitmapDrawable) {
            return drawable.bitmap
        }
        val bmp = Bitmap.createBitmap(
            drawable.intrinsicWidth, drawable.intrinsicHeight,
            Bitmap.Config.ARGB_8888
        )
        val c = Canvas(bmp)
        drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
        drawable.draw(c)
        return bmp
    }

}
android image design-patterns android-jetpack-compose tile
3个回答
11
投票

根据拉菲尔的回答,我能够想出一些更简洁的东西。希望 Compose 能够提供一些内置功能,让这一切在未来变得更简单。

val image = ImageBitmap.imageResource(R.drawable.my_image)
val brush = remember(image) { ShaderBrush(ImageShader(image, TileMode.Repeated, TileMode.Repeated)) }
Box(Modifier
    .fillMaxSize()
    .background(brush)) {
}

9
投票

如果你想使用原生画布,你可以在 jetpack compose 中执行类似的操作。


    Canvas(
        modifier = Modifier
            .fillMaxSize()
    ) {
    
        val paint = Paint().asFrameworkPaint().apply {
            isAntiAlias = true
            shader = ImageShader(pattern, TileMode.Repeated, TileMode.Repeated)
        }
    
        drawIntoCanvas {
            it.nativeCanvas.drawPaint(paint)
        }
        paint.reset()
    }

如果您想将重复限制在一定的高度和宽度,您可以在画布中使用剪辑修改器,如下所示,否则它将填满整个屏幕。


    Canvas(
        modifier = Modifier
            .width(300.dp)
            .height(200.dp)
            .clip(RectangleShape)
    ) {
        ----
    }


0
投票

我找不到任何现有的扩展来加载矢量资源并将其转换为组成 ImageBitmap,因此这里是如何基于加载 BitmapDrawable:

的标准扩展来执行此操作的示例
fun ImageBitmap.Companion.vectorImageResource(res: Resources, @DrawableRes id: Int): ImageBitmap {
    return requireNotNull(ResourcesCompat.getDrawable(res, id, null))
        .toBitmap()
        .asImageBitmap()
}

@Composable
fun ImageBitmap.Companion.vectorImageResource(@DrawableRes id: Int): ImageBitmap {
    val context = LocalContext.current
    val value = remember { TypedValue() }
    context.resources.getValue(id, value, true)
    val key = value.string!!.toString() // image resource must have resource path.
    return remember(key) { vectorImageResource(context.resources, id) }
}

然后可以将生成的 ImageBitmap 传递给上面 Erik Uggeldahl 的示例。

val brush = remember(image) { ShaderBrush(ImageShader(image, TileMode.Repeated, TileMode.Repeated)) }
© www.soinside.com 2019 - 2024. All rights reserved.