התאמה אישית של תמונה

אפשר להתאים אישית תמונות באמצעות מאפיינים ב-Image composable (contentScale, colorFilter). אפשר גם להשתמש ב-Modifiers הקיים כדי להחיל אפקטים שונים על Image. אפשר להשתמש בשינויים בכל רכיב שאפשר להרכיב, ולא רק ברכיב שאפשר להרכיב Image, בעוד ש-contentScale ו-colorFilter הם פרמטרים מפורשים ברכיב שאפשר להרכיב Image.

היקף התוכן

מציינים אפשרות contentScale לחיתוך או לשינוי של קנה המידה של התמונה בתוך הגבולות שלה. כברירת מחדל, אם לא מציינים contentScale אפשרות, המערכת תשתמש ב-ContentScale.Fit.

בדוגמה שלמטה, הרכיב Image מוגבל לגודל של 150dp עם גבול, והרקע מוגדר לצהוב ברכיב Image כדי להציג את האפשרויות השונות של ContentScale בטבלה שלמטה.

val imageModifier = Modifier
    .size(150.dp)
    .border(BorderStroke(1.dp, Color.Black))
    .background(Color.Yellow)
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Fit,
    modifier = imageModifier
)

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

תמונת המקור תמונת המקור לאורך תמונת מקור לרוחב
ContentScale תוצאה – תמונה לאורך: תוצאה – תמונה לרוחב:
ContentScale.Fit: שינוי גודל התמונה באופן אחיד, תוך שמירה על יחס הגובה-רוחב (ברירת מחדל). אם התוכן קטן מהגודל, התמונה מוגדלת כדי להתאים לגבולות. ContentScale.Fit portrait ‫ContentScale.Fit landscape
ContentScale.Crop: חיתוך התמונה למרכז כדי שתתאים לשטח הזמין. ContentScale.Crop portrait ContentScale.Crop landscape
ContentScale.FillHeight: שינוי קנה המידה של המקור תוך שמירה על יחס הגובה-רוחב, כך שהגבולות יתאימו לגובה היעד. ContentScale.FillHeight portrait ‫ContentScale.FillHeight landscape
ContentScale.FillWidth: שינוי קנה המידה של המקור תוך שמירה על יחס הגובה-רוחב, כך שהגבולות יתאימו לרוחב היעד. ContentScale.FillWidth portrait ‫ContentScale.FillWidth landscape
ContentScale.FillBounds: שינוי קנה המידה של התוכן באופן אנכי ואופקי לא אחיד כדי למלא את גבולות היעד. (הערה: אם תמקמו תמונות במאגרי תמונות שלא תואמים ליחס המדויק של התמונה, התמונות יעוותו) ‫ContentScale.FillBounds portrait ‫ContentScale.FillBounds landscape
ContentScale.Inside: שינוי קנה המידה של המקור כדי לשמור על יחס הגובה-רוחב בתוך גבולות היעד. אם המקור קטן מהיעד או שווה לו בשני הממדים, הוא מתנהג באופן דומה ל-None. התוכן תמיד יהיה כלול בגבולות. אם התוכן קטן מהגבולות, לא יחול שינוי גודל. תמונת המקור גדולה יותר מהגבולות: ContentScale.Inside portrait, source image larger than bounds תמונת המקור קטנה יותר מהגבולות: ContentScale.Inside portrait, source image smaller than bounds תמונת המקור גדולה יותר מהגבולות: ContentScale.Inside landscape, source image larger than bounds תמונת המקור קטנה יותר מהגבולות: ContentScale.Inside landscape, source image smaller than bounds
ContentScale.None: לא מוחלים שינוי גודל על המקור. אם התוכן קטן יותר מגבולות היעד, הוא לא יוגדל כדי להתאים לאזור. תמונת המקור גדולה יותר מהגבולות: ‫ContentScale.None portrait, source image larger than bounds תמונת המקור קטנה יותר מהגבולות: ‫ContentScale.None לאורך, תמונת המקור קטנה יותר מהגבולות תמונת המקור גדולה יותר מהגבולות: ContentScale.None landscape, source image larger than bounds תמונת המקור קטנה יותר מהגבולות: ‫ContentScale.None landscape, source image smaller than bounds

חיתוך של רכיב Image שאפשר להרכיב לצורה

כדי להתאים תמונה לצורה, משתמשים במאפיין clip המובנה. כדי לחתוך תמונה לצורה של עיגול, משתמשים בModifier.clip(CircleShape):

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(200.dp)
        .clip(CircleShape)
)

חיתוך תמונה באמצעות CircleShape
איור 1: חיתוך תמונה באמצעות CircleShape

צורה עם פינות מעוגלות – משתמשים ב-Modifier.clip(RoundedCornerShape(16.dp)) עם גודל הפינות שרוצים לעגל:

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(200.dp)
        .clip(RoundedCornerShape(16.dp))
)

חיתוך תמונה באמצעות RoundedCornerShape
איור 2: חיתוך תמונה באמצעות RoundedCornerShape

אפשר גם ליצור צורת חיתוך משלכם על ידי הרחבת Shape וציון Path לצורה לחיתוך:

class SquashedOval : Shape {
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline {
        val path = Path().apply {
            // We create an Oval that starts at ¼ of the width, and ends at ¾ of the width of the container.
            addOval(
                Rect(
                    left = size.width / 4f,
                    top = 0f,
                    right = size.width * 3 / 4f,
                    bottom = size.height
                )
            )
        }
        return Outline.Generic(path = path)
    }
}

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(200.dp)
        .clip(SquashedOval())
)

חיתוך תמונה עם צורה של נתיב בהתאמה אישית
איור 3: חיתוך תמונה עם צורת נתיב מותאמת אישית

הוספת גבול לרכיב Image שאפשר להרכיב

פעולה נפוצה היא לשלב את Modifier.border() עם Modifier.clip() כדי ליצור מסגרת סביב תמונה:

val borderWidth = 4.dp
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(150.dp)
        .border(
            BorderStroke(borderWidth, Color.Yellow),
            CircleShape
        )
        .padding(borderWidth)
        .clip(CircleShape)
)

חיתוך תמונה והוספת גבול מסביב
איור 4: חיתוך תמונה והוספת גבול מסביב

אם רוצים ליצור מסגרת עם מעבר צבעים, אפשר להשתמש ב-API‏ Brush כדי לצייר מסגרת עם מעבר צבעים של קשת מסביב לתמונה:

val rainbowColorsBrush = remember {
    Brush.sweepGradient(
        listOf(
            Color(0xFF9575CD),
            Color(0xFFBA68C8),
            Color(0xFFE57373),
            Color(0xFFFFB74D),
            Color(0xFFFFF176),
            Color(0xFFAED581),
            Color(0xFF4DD0E1),
            Color(0xFF9575CD)
        )
    )
}
val borderWidth = 4.dp
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(150.dp)
        .border(
            BorderStroke(borderWidth, rainbowColorsBrush),
            CircleShape
        )
        .padding(borderWidth)
        .clip(CircleShape)
)

גבול של עיגול עם צבעי קשת שמוצגים באופן הדרגתי
איור 5: גבול בצורת עיגול עם מעבר צבעים בצבעי הקשת

הגדרת יחס גובה-רוחב מותאם אישית

כדי לשנות את יחס הגובה-רוחב של תמונה, משתמשים ב-Modifier.aspectRatio(16f/9f) כדי לספק יחס גובה-רוחב מותאם אישית לתמונה (או לכל רכיב שאפשר להוסיף).

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    modifier = Modifier.aspectRatio(16f / 9f)
)

שימוש ב-Modifier.aspectRatio(16f/9f) ב-Image
איור 6: שימוש ב-Modifier.aspectRatio(16f/9f) בתמונה

מסנן צבעים – שינוי צבעי הפיקסלים של התמונה

לרכיב Image Composable יש פרמטר colorFilter שיכול לשנות את הפלט של פיקסלים בודדים בתמונה.

גוון של תמונה

השימוש ב-ColorFilter.tint(color, blendMode) יחיל מצב מיזוג עם הצבע שצוין על רכיב ה-Image. האפליקציה ColorFilter.tint(color, blendMode) משתמשת ב-BlendMode.SrcIn כדי להוסיף גוון לתוכן, כלומר הצבע שסופק יוצג במקום שבו התמונה מוצגת במסך. האפשרות הזו שימושית לסמלים ולווקטורים שצריך לעצב בצורה שונה.

Image(
    painter = painterResource(id = R.drawable.baseline_directions_bus_24),
    contentDescription = stringResource(id = R.string.bus_content_description),
    colorFilter = ColorFilter.tint(Color.Yellow)
)

המסנן ColorFilter.tint הוחל עם BlendMode.SrcIn
איור 7: ColorFilter.tint applied with BlendMode.SrcIn

תוצאות אחרות של BlendMode יוצרות אפקטים שונים. לדוגמה, הגדרת BlendMode.Darken עם Color.Green בתמונה יוצרת את התוצאה הבאה:

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.tint(Color.Green, blendMode = BlendMode.Darken)
)

גוון ירוק עם BlendMode.Darken
איור 8: גוון ירוק עם BlendMode.Darken

מידע נוסף על מצבי השילוב השונים זמין במאמרי העזרה בנושא BlendMode.

החלת פילטר Image עם מטריצת צבע

משנים את התמונה באמצעות האפשרות ColorFilter מטריצת צבעים. לדוגמה, כדי להחיל פילטר שחור-לבן על התמונות, אפשר להשתמש ב-ColorMatrix ולהגדיר את הרוויה ל-0f.

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0f) })
)

מטריצת צבעים עם רוויה 0 (תמונה בשחור-לבן)
איור 9: מטריצת צבעים עם רוויה 0 (תמונה בשחור-לבן)

התאמת הניגודיות או הבהירות של רכיב Image שאפשר להרכיב

כדי לשנות את הניגודיות והבהירות של תמונה, אפשר להשתמש בתג ColorMatrix כדי לשנות את הערכים:

val contrast = 2f // 0f..10f (1 should be default)
val brightness = -180f // -255f..255f (0 should be default)
val colorMatrix = floatArrayOf(
    contrast, 0f, 0f, 0f, brightness,
    0f, contrast, 0f, 0f, brightness,
    0f, 0f, contrast, 0f, brightness,
    0f, 0f, 0f, 1f, 0f
)
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.colorMatrix(ColorMatrix(colorMatrix))
)

התאמה של הבהירות והניגודיות של התמונה באמצעות ColorMatrix
איור 10: בהירות וניגודיות מותאמות של תמונה באמצעות ColorMatrix

היפוך צבעים של רכיב Image

כדי להפוך את הצבעים של תמונה, מגדירים את ColorMatrix להפיכת הצבעים:

val colorMatrix = floatArrayOf(
    -1f, 0f, 0f, 0f, 255f,
    0f, -1f, 0f, 0f, 255f,
    0f, 0f, -1f, 0f, 255f,
    0f, 0f, 0f, 1f, 0f
)
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.colorMatrix(ColorMatrix(colorMatrix))
)

היפוך צבעים בתמונה
איור 11: צבעים הפוכים בתמונה

טשטוש של Image קומפוזבל

כדי לטשטש תמונה, משתמשים ב-Modifier.blur() ומציינים את radiusX ואת radiusY, שקובעים את רדיוס הטשטוש בכיוון האופקי והאנכי בהתאמה.

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(150.dp)
        .blur(
            radiusX = 10.dp,
            radiusY = 10.dp,
            edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp))
        )
)

אפקט הטשטוש הוחל על התמונה
איור 12: BlurEffect applied to image

כשמטשטשים Images, מומלץ להשתמש ב-BlurredEdgeTreatment(Shape) במקום ב-BlurredEdgeTreatment.Unbounded, כי האחרון משמש לטשטוש של עיבודים שרירותיים שאמורים לעבור עיבוד מחוץ לגבולות של התוכן המקורי. במקרה של תמונות, סביר להניח שהן לא יוצגו מחוץ לגבולות התוכן, אבל יכול להיות שיהיה צורך להבחין בין המקרים האלה כשמטשטשים מלבן מעוגל.

לדוגמה, אם מגדירים את BlurredEdgeTreatment ללא מוגבל בתמונה שלמעלה, הקצוות של התמונה מטושטשים במקום חדים:

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(150.dp)
        .blur(
            radiusX = 10.dp,
            radiusY = 10.dp,
            edgeTreatment = BlurredEdgeTreatment.Unbounded
        )
        .clip(RoundedCornerShape(8.dp))
)

BlurEdgeTreatment.Unbounded
איור 13: BlurEdgeTreatment.Unbounded