تخصيص صورة

يمكنك تخصيص الصور باستخدام خصائص في دالة 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