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

אפשר להתאים אישית תמונות באמצעות מאפיינים ב-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.Crop: חיתוך התמונה למרכז כדי שתתאים לשטח הזמין. תמונה לאורך שנחתכה כך שתתאים למסגרת ריבועית, ומוצג בה רק החלק המרכזי של התמונה. תמונה לרוחב שנחתכה כדי למלא מסגרת מרובעת, כך שמוצג רק החלק המרכזי של התמונה.
ContentScale.FillHeight: שינוי קנה המידה של המקור תוך שמירה על יחס הגובה-רוחב, כך שהגבולות יתאימו לגובה היעד. תמונה לאורך שמוגדלת כדי למלא את הגובה של מסגרת ריבועית, שבה רואים את התמונה המלאה עם רקע צהוב בצד ימין ובצד שמאל. תמונה לרוחב שמוגדלת כדי למלא את הגובה של מסגרת ריבועית, והצדדים שלה נחתכים.
ContentScale.FillWidth: שינוי קנה המידה של המקור תוך שמירה על יחס הגובה-רוחב, כך שהגבולות יתאימו לרוחב היעד. תמונה לאורך שמשנה את הגודל שלה כדי למלא את הרוחב של פריים מרובע, עם חיתוך של החלק העליון והתחתון. תמונה לרוחב ששונתה בה הגודל כדי למלא את הרוחב של מסגרת מרובעת, שבה רואים את התמונה המלאה עם רקע צהוב בחלק העליון והתחתון.
ContentScale.FillBounds: שינוי קנה המידה של התוכן באופן אנכי ואופקי לא אחיד כדי למלא את גבולות היעד. (הערה: אם מציבים תמונות במאגרי תמונות שלא תואמים ליחס המדויק של התמונה, התמונות מעוותות). תמונה לאורך שעברה עיוות כדי למלא מסגרת ריבועית, עם מתיחה של התמונה. תמונה לרוחב שעברה עיוות כדי למלא מסגרת מרובעת, כך שהתמונה נמתחת.
ContentScale.Inside: שינוי קנה המידה של המקור כדי לשמור על יחס הגובה-רוחב בתוך גבולות היעד. אם המקור קטן מהיעד או שווה לו בשני הממדים, הוא מתנהג באופן דומה ל-None. התוכן תמיד יהיה בתוך הגבולות. אם התוכן קטן מהגבולות, לא יחול שינוי גודל. תמונת המקור גדולה יותר מהגבולות: תמונה לאורך, שהייתה במקור גדולה יותר מהגבולות הריבועיים שלה, הוקטנה כדי להתאים לגבולות תוך שמירה על יחס הגובה-רוחב, ומוצג רקע צהוב בצדדים. תמונת המקור קטנה יותר מהגבולות: תמונה לאורך, שהייתה קטנה יותר מהגבולות הריבועיים שלה, מוצגת בגודל המקורי שלה בתוך המסגרת, עם רקע צהוב סביבה. תמונת המקור גדולה יותר מהגבולות: תמונה אופקית, שהייתה במקור גדולה יותר מהגבולות המרובעים שלה, הוקטנה כדי להתאים לגבולות תוך שמירה על יחס הגובה-רוחב, ומוצג רקע צהוב בחלק העליון והתחתון שלה. תמונת המקור קטנה יותר מהגבולות: תמונה לרוחב, שהייתה קטנה יותר מהגבולות הריבועיים שלה, מוצגת בגודל המקורי שלה בתוך המסגרת, עם רקע צהוב סביבה.
ContentScale.None: לא חלים שינויי גודל על המקור. אם התוכן קטן יותר מגבולות היעד, הוא לא יוגדל כדי להתאים לאזור. תמונת המקור גדולה יותר מהגבולות: תמונה לאורך, שהייתה במקור גדולה יותר מהגבולות המרובעים שלה, מוצגת בגודל המקורי שלה, וחלקים ממנה חורגים מהחלק העליון והתחתון של המסגרת. תמונת המקור קטנה יותר מהגבולות: תמונה לאורך, שהייתה קטנה יותר מהגבולות הריבועיים שלה, מוצגת בגודל המקורי שלה בתוך המסגרת, עם רקע צהוב סביבה. תמונת המקור גדולה יותר מהגבולות: תמונה לרוחב, שהייתה במקור גדולה יותר מהגבולות המרובעים שלה, מוצגת בגודל המקורי שלה, וחלקים ממנה חורגים מהגבולות השמאלי והימני של המסגרת. תמונת המקור קטנה יותר מהגבולות: תמונה לרוחב, שהייתה קטנה יותר מהגבולות הריבועיים שלה, מוצגת בגודל המקורי שלה בתוך המסגרת, עם רקע צהוב סביבה.

חיתוך של רכיב 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)
)

תמונה של כלב שנחתכה בצורה של עיגול מושלם.
איור 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))
)

תמונה מרובעת של כלב עם פינות מעוגלות.
איור 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)
)

תמונה ריבועית של כלב, שהומרה ליחס גובה-רוחב של 16:9, כך שהיא רחבה יותר וקצרה יותר.
איור 6. שימוש ב-Modifier.aspectRatio(16f/9f) ב-Image.

פילטר צבע: שינוי צבעי הפיקסלים של התמונה

לרכיב Image יש פרמטר 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)
)

תמונה של אוטובוס עם גוון צהוב.
איור 7. ההגדרה ColorFilter.tint הוחלה מהיחידה 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. Color.Green tint עם 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) })
)

כלב עם מסנן שחור-לבן, ללא רוויית צבע.
איור 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))
)

כלב עם בהירות וניגודיות מוגדלות, שגורמות לו להיראות חי יותר.
איור 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 an image.

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

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

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

תמונה מטושטשת של כלב, כשהטשטוש חורג מגבולות התמונה המקורית ויוצר קצוות מטושטשים.
איור 13. BlurEdgeTreatment.Unbounded.