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

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

התאמה לגודל התוכן

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

בדוגמה הבאה, ה-composable של התמונה מוגבל לגודל 150dp עם שוליים, והרקע מוגדר לצהוב ב-composable של 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 לרוחב
ContentScale.FillWidth: שינוי קנה המידה של המקור תוך שמירה על יחס הגובה-רוחב, כך שהגבולות יהיו תואמים לרוחב היעד. ContentScale.FillWidth portrait ContentScale.FillWidth לרוחב
ContentScale.FillBounds: שינוי קנה המידה של התוכן באופן לא אחיד אנכית ואופקית כדי למלא את גבולות היעד. (הערה: הפעולה הזו גורמת לעיוות של תמונות אם מניחים אותן בקונטיינרים שלא תואמים ליחס המדויק של התמונה) ContentScale.FillBounds לאורך ContentScale.FillBounds לרוחב
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 portrait, source image smaller than bounds תמונת המקור גדולה מהגבולות: ContentScale.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)
)

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

גוון Color.Green עם BlendMode.Darken
איור 8: Color.Green tint with 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))
        )
)

אפקט Blur הוחל על התמונה
איור 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))
)

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