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

אתם יכולים להתאים אישית תמונות באמצעות מאפיינים של פונקציית קומפוזבילית Image (contentScale, colorFilter). אתם יכולים גם להחיל משתני שינוי קיימים כדי להחיל אפקטים שונים על Image. אפשר להשתמש ב-Modifiers בכל תוכן קומפוזבילי, לא רק בתוכן הקומפוזבילי 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 לצורה

כדי להתאים תמונה לצורה, משתמשים ב-modifier המובנה 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) כדי לספק יחס גובה-רוחב מותאם אישית לתמונה (או לכל רכיב Composable).

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.

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

לרכיב ה-Composable‏ 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.

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

כשמטשטשים את 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.