ช่างทาสีตามสั่ง

ใน Compose จะใช้Painterออบเจ็กต์เพื่อแสดงสิ่งที่วาดได้ (แทนที่ API ของ Drawable ที่กำหนดไว้ใน Android) และมีอิทธิพลต่อ การวัดและการจัดวางของ Composable ที่เกี่ยวข้องซึ่งใช้ออบเจ็กต์นั้น A BitmapPainter จะใช้ ImageBitmap ที่วาด Bitmap บนหน้าจอได้

สำหรับกรณีการใช้งานส่วนใหญ่ การใช้ painterResource() ด้านบนจะแสดงผล Painter ที่ถูกต้องสำหรับชิ้นงาน (เช่น BitmapPainter หรือ VectorPainter) ดูข้อมูลเพิ่มเติม เกี่ยวกับความแตกต่างระหว่างทั้ง 2 รายการได้ที่ส่วนImageBitmap กับ ImageVector

Painter แตกต่างจาก DrawModifier ซึ่งจะวาดภายในขอบเขตที่กำหนดไว้อย่างเคร่งครัด และไม่มีผลต่อการวัดหรือเลย์เอาต์ของ Composable

หากต้องการสร้าง Painter ที่กำหนดเอง ให้ขยายคลาส Painter และใช้เมธอด onDraw ซึ่งอนุญาตให้เข้าถึง DrawScope เพื่อวาดกราฟิกที่กำหนดเอง นอกจากนี้ คุณยังลบล้าง intrinsicSize ได้ด้วย ซึ่งจะใช้เพื่อ มีอิทธิพลต่อ Composable ที่มีอยู่

class OverlayImagePainter constructor(
    private val image: ImageBitmap,
    private val imageOverlay: ImageBitmap,
    private val srcOffset: IntOffset = IntOffset.Zero,
    private val srcSize: IntSize = IntSize(image.width, image.height),
    private val overlaySize: IntSize = IntSize(imageOverlay.width, imageOverlay.height)
) : Painter() {

    private val size: IntSize = validateSize(srcOffset, srcSize)
    override fun DrawScope.onDraw() {
        // draw the first image without any blend mode
        drawImage(
            image,
            srcOffset,
            srcSize,
            dstSize = IntSize(
                this@onDraw.size.width.roundToInt(),
                this@onDraw.size.height.roundToInt()
            )
        )
        // draw the second image with an Overlay blend mode to blend the two together
        drawImage(
            imageOverlay,
            srcOffset,
            overlaySize,
            dstSize = IntSize(
                this@onDraw.size.width.roundToInt(),
                this@onDraw.size.height.roundToInt()
            ),
            blendMode = BlendMode.Overlay
        )
    }

    /**
     * Return the dimension of the underlying [ImageBitmap] as it's intrinsic width and height
     */
    override val intrinsicSize: Size get() = size.toSize()

    private fun validateSize(srcOffset: IntOffset, srcSize: IntSize): IntSize {
        require(
            srcOffset.x >= 0 &&
                srcOffset.y >= 0 &&
                srcSize.width >= 0 &&
                srcSize.height >= 0 &&
                srcSize.width <= image.width &&
                srcSize.height <= image.height
        )
        return srcSize
    }
}

ตอนนี้เรามีPainterที่กำหนดเองแล้ว เราสามารถวางซ้อนรูปภาพใดก็ได้บนรูปภาพต้นฉบับได้ดังนี้

val rainbowImage = ImageBitmap.imageResource(id = R.drawable.rainbow)
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog)
val customPainter = remember {
    OverlayImagePainter(dogImage, rainbowImage)
}
Image(
    painter = customPainter,
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier.wrapContentSize()
)

ผลลัพธ์ของการรวมรูปภาพ 2 รูปเข้าด้วยกันด้วย Painter ที่กำหนดเองจะแสดงอยู่ด้านล่าง

CustomPainter ที่ซ้อนทับรูปภาพ 2 รูป
รูปที่ 1: CustomPainter ที่วางซ้อนรูปภาพ 2 รูปไว้ด้านบนของกันและกัน

นอกจากนี้ คุณยังใช้ Painter ที่กำหนดเองกับ Modifier.paint(customPainter) เพื่อวาดเนื้อหาไปยัง Composable ได้ดังนี้

val rainbowImage = ImageBitmap.imageResource(id = R.drawable.rainbow)
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog)
val customPainter = remember {
    OverlayImagePainter(dogImage, rainbowImage)
}
Box(
    modifier =
    Modifier.background(color = Color.Gray)
        .padding(30.dp)
        .background(color = Color.Yellow)
        .paint(customPainter)
) { /** intentionally empty **/ }