צבעים בהתאמה אישית

בכתיבה, אובייקט Painter משמש כדי לייצג משהו שאפשר לצייר (תחליף לממשקי ה-API של Drawable שמוגדרים ב-Android) ומשפיעים מדידה ופריסה של התוכן הקומפוזבילי התואם שמשתמש בו . א' BitmapPainter לוקחת ImageBitmap שניתן לצייר Bitmap על המסך.

ברוב תרחישי השימוש, שימוש בפונקציה painterResource() שלמעלה מחזיר את הערך הציור של הנכס (למשל BitmapPainter או VectorPainter). לקבלת מידע נוסף מידע על ההבדלים בין השניים - קראו את הקטע ImageBitmap לעומת ImageVector.

Painter שונה מ-DrawModifier, שמיוצג רק בתוך הגבולות שנקבעו לו ואין להם השפעה על המדידה או הפריסה של התוכן הקומפוזבילי.

כדי ליצור צבע בהתאמה אישית, מרחיבים את המחלקה Painter ומטמיעים את השיטה onDraw, שמאפשרת גישה לשיטה DrawScope כדי לבצע שרטוט בהתאמה אישית גרפי. אפשר גם לשנות את intrinsicSize, שישמש ל: להשפיע על הקומפוזבילי שהוא כלול ב:

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()
)

הפלט של השילוב בין שתי התמונות עם כלי ציור בהתאמה אישית נראה למטה:

צבע בהתאמה אישית שמוסיף שכבת-על של שתי תמונות אחת על השנייה
איור 1: כלי לצביעה בהתאמה אישית שמציג שתי תמונות אחת על השנייה

אפשר להשתמש בכלי ציור בהתאמה אישית גם עם Modifier.paint(customPainter) כדי לצייר את התוכן לתוכן קומפוזבילי באופן הבא:

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 **/ }