Каждый контейнер может быть вертикальным (столбец) или горизонтальным (строка), а такие компоненты, как текст, значки и изображения, отображаются на основе атрибутов JSON.
Обновлено
Вот упрощенный пример моего JSON:
Код: Выделить всё
{
"id": "productWrapper",
"component": "container",
"direction": "vertical",
"components": [
{
"id": "productWrapper4",
"component": "container",
"direction": "horizontal",
"components": [
{
"id": "rockiesLogo",
"component": "image",
"url": "https://upload.wikimedia.org/wikipedia/en/f/f6/Colorado_Rockies_logo.svg",
"width": 130
},
{
"id": "plusIcon",
"component": "icon",
"name": "add"
},
{
"id": "mlbLogo",
"component": "image",
"url": "https://upload.wikimedia.org/wikipedia/en/3/3e/MLB.TV_logo.png",
"width": "100%",
"height": "100%",
"alignment": "left"
}
]
}
]
}
Но в Android Jetpack Compose оно всегда масштабируется или обрезается, чтобы соответствовать ширине строки.
Вот что я получаю:

Платформа
Результат
Изображение MLB.TV выходит за край карточки (переполнение разрешено).
Изображение остается полностью внутри строки, уменьшаясь до нужного размера.
Ожидаемое (ссылка на iOS):

Код: Выделить всё
@Composable
fun FilteredComponent(component: Component) {
when (component.component) {
"container" -> ContainerUI(component)
"image" -> ImageUI(component)
"icon" -> IconUI(Icons.Default.Add, contentDescription = "Add")
}
}
Код: Выделить всё
@Composable
fun ContainerUI(component: Component) {
when (component.direction) {
"horizontal" -> Row(
modifier = Modifier
.fillMaxWidth()
.background(Color(0x33FF0000))
.padding(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
component.components.forEach { FilteredComponent(it) }
}
else -> Column(
modifier = Modifier
.fillMaxWidth()
.background(Color(0x2200FF00))
.padding(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
component.components.forEach { FilteredComponent(it) }
}
}
}
Код: Выделить всё
@Composable
fun ImageUI(component: Component) {
val configuration = LocalConfiguration.current
val density = LocalDensity.current
val screenWidthPx = with(density) { configuration.screenWidthDp.dp.toPx().toInt() }
val wantsFullDeviceWidth = component.height.isPercentage() && component.width.isPercentage() && component.alignment == Alignment.LEFT
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(0.dp)
) {
AsyncImage(
model = component.url,
contentDescription = component.id,
contentScale = if (wantsFullDeviceWidth) ContentScale.FillWidth else ContentScale.Fit,
modifier = Modifier
.then(
if (wantsFullDeviceWidth) {
Modifier.layout { measurable, constraints ->
val expanded = constraints.copy(
minWidth = screenWidthPx,
maxWidth = screenWidthPx
)
val placeable = measurable.measure(expanded)
layout(constraints.maxWidth, placeable.height) {
placeable.placeRelative(0, 0)
}
}
} else Modifier
)
.border(1.dp, Color.Blue)
.height(100.dp)
)
}
}
Похоже, что Compose применяет ограничения ширины во время измерения, поэтому изображение никогда не отображается за пределами родительского элемента.
Как сделать компонуемый дочерний элемент (в данном случае изображение) визуально переполняющим справа, за пределами измеренной ширины родительской строки — аналогично тому, как SwiftUI позволяет представлениям рисовать за пределами границ контейнера?
В идеале:
Родительский макет не должен расширяться, чтобы соответствовать переполнению.
Родственные элементы в строке не должны смещаться.
Только переполняющее изображение должно отображаться за пределами родительского макета. ширина.
Работает с динамическими макетами JSON (контейнеры создаются рекурсивно).
Подробнее здесь: https://stackoverflow.com/questions/797 ... jetpack-co
Мобильная версия