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

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

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

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

תמונה של אוטובוס עם גוון צהוב.
איור 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 composable

כדי לטשטש תמונה, משתמשים ב-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.