تخصيص صورة

يمكنك تخصيص الصور باستخدام خصائص في عنصر Image المركّب (contentScale وcolorFilter). يمكنك أيضًا تطبيق المعدِّلات الحالية لتطبيق تأثيرات مختلفة على 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 لرسم حدود متدرّجة بألوان قوس قزح حول الصورة:

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 مطبّق على صورة

عند تمويه 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