Настройка изображения

Вы можете настраивать изображения, используя свойства компонуемого объекта Image ( contentScale , colorFilter ). Вы также можете применять существующие модификаторы для применения различных эффектов к вашему Image . Модификаторы можно использовать для любого компонуемого объекта , а не только для объекта Image , тогда как contentScale и colorFilter являются явными параметрами компонуемого объекта Image .

Шкала содержания

Укажите параметр contentScale , чтобы обрезать или изменить масштаб изображения в пределах его границ. По умолчанию, если параметр contentScale не указан, используется ContentScale.Fit .

В следующем примере размер компонуемого Image ограничен 150 dp с рамкой, а фон для компонуемого 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. Вырезанное изображение с рамкой вокруг него.

Чтобы создать градиентную рамку, вы можете использовать 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)
)

Квадратное изображение собаки, преобразованное в соотношение сторон 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 с цветовой матрицей

Преобразуйте изображение с помощью параметра ColorMatrix 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 .
{% дословно %} {% endverbatim %} {% дословно %} {% endverbatim %}