Как уменьшить весь контент пользовательского интерфейса, чтобы он поместился в области предварительного просмотра в Jetpack Compose?

Я реализую экран выбора темы для своего приложения. Идея состоит в том, чтобы предоставить пользователю различные темы, из которых он может выбирать, и отобразить предварительный просмотр двух экранов, чтобы пользователь мог видеть, как будет выглядеть тема после ее выбора.

Я показываю этот главный экран в качестве предварительного просмотра:

Вот как выглядит мой экран выбора темы:

Я хочу уменьшить содержимое главного экрана, чтобы отобразить все содержимое главного экрана в доступной области предварительного просмотра выбора темы.

Я пробовал использовать Modifier.scale(0.4f) и Modifier.graphicsLayer(scaleX = 0.4f, scaleY = 0.4f), но это только уменьшает то, что уже видно.

Одна из идей, которая, похоже, работает, — использовать локального поставщика для предоставления коэффициента масштабирования пользовательскому интерфейсу Compose следующим образом:

val LocalScaleFactor = compositionLocalOf { 1f }

@Composable
fun ScaleFactorProvider(
    scaleFactor: Float = 1f,
    content: @Composable () -> Unit,
) {
    CompositionLocalProvider(
        LocalScaleFactor provides scaleFactor,
        content = content
    )
}

val Int.scaleDp: Dp
    @Composable
    get() = (this * localScaleFactor).dp

val Int.scaleSp: TextUnit
    @Composable
    get() = (this * localScaleFactor).sp

val localScaleFactor: Float
    @Composable get() = LocalScaleFactor.current
ScaleFactorProvider(0.4f) {
   HomeScreenPreview()
}

Хотя этот метод работает, он требует значительных изменений кода. Мне приходится использовать scaleDp и scaleSP везде, а для некоторых представлений, таких как Icon, для которых я обычно не указываю размер и просто использую размер по умолчанию, теперь мне нужно определить размер. Это довольно неудобно.

Есть ли альтернативный способ уменьшить размеры всего дерева пользовательского интерфейса, чтобы он соответствовал доступному родительскому размеру в Jetpack Compose?

Редактировать 1:

Я попробовал то, что @Leviathan предложил в комментарии. Это работает, но из-за этого сложно возложить ответственность на пользовательский интерфейс. Мой текущий пользовательский интерфейс выглядит примерно так

  • Столбец
    • Ряд
      • Вес коробки 1f
      • Вес коробки 1f
    • Остальная часть пользовательского интерфейса

Теперь мне нужно переместить содержимое строки наружу

  • Коробка
    • Столбец
      • Пустая коробка 1f вес
    • Остальная часть пользовательского интерфейса
    • Предварительный просмотр слева
    • Предварительный просмотр справа

После уменьшения масштаба оба предварительного просмотра будут в центре, и мне нужно указать смещения по x и y в том месте, где я хочу.

Проблема с этим методом заключается в том, что, поскольку поле предварительного просмотра привязано к родительскому элементу, выравнивание может быть отключено в зависимости от измерения пользовательского устройства.

Что произойдет, если вы нарисуете предварительный просмотр в полном размере, занимая весь экран, а затем уменьшите его?

Leviathan 08.07.2024 09:30

взгляните на макет BoxWithConstraints, такой же, как у box, с возможностью установки минимальной и максимальной ширины и высоты: foso.github.io/Jetpack-Compose-Playground/foundation/layout/‌​…

Hezy Ziv 08.07.2024 10:53

@Leviathan Только что попробовал это решение. Это работает, но из-за этого сложно возложить ответственность на пользовательский интерфейс. Мой текущий пользовательский интерфейс выглядит примерно так: Столбец - Строка - Вес поля 1f - Вес поля 1f - Остальная часть пользовательского интерфейса Теперь мне нужно переместить содержимое строки наружу - Поле - Столбец - Пустое поле веса 1f - Остальная часть пользовательского интерфейса - Предварительный просмотр слева в поле - Предварительный просмотр справа После уменьшения масштаба оба предварительного просмотра будут в центре, и мне нужно указать смещения по осям x и y в том месте, где я хочу, чтобы они были. Когда я тестировал это на экранах разных размеров, выравнивание было немного неправильным в зависимости от устройства.

Argus Waikhom 08.07.2024 18:35
2
3
121
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Попробуйте добавить собственный Density к вашему составному элементу.

Density реализация:

private data class MyDensity(override val density: Float, override val fontScale: Float) : Density

Сборный:

val scale = 0.4f
val curDensity = LocalDensity.current
val myDensity = MyDensity(curDensity.density * scale, curDensity.fontScale)
CompositionLocalProvider(LocalDensity provides myDensity) {
    //Content
}

Редактировать:

Пример:

private data class MyDensity(override val density: Float, override val fontScale: Float) : Density

@Composable
fun ScalableScreen() {
    var scale by remember { mutableFloatStateOf(1f) }
    fun doScale(value: Float) {
        scale *= value
    }
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Row {
            Button(onClick = { doScale(0.9f) }) { Text("-") }
            Button(onClick = { doScale(1.1f) }) { Text("+") }
        }
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier.fillMaxSize(scale),
        ) {
            val curDensity = LocalDensity.current
            val myDensity = MyDensity(curDensity.density * scale, curDensity.fontScale)
            CompositionLocalProvider(LocalDensity provides myDensity) {
                Content(Color.DarkGray, Color.LightGray)
            }
        }
    }
}

@Composable
private fun Content(color1: Color, color2: Color, ) {
    Column(
        modifier = Modifier.background(color1).padding(8.dp)
    ) {
        Row {
            repeat(2) {
                Box(
                    modifier = Modifier.height(100.dp).weight(1f).padding(8.dp).background(color2)
                ) {
                    Button(onClick = {}) { Text(text = "Button $it") }
                }
            }
        }
        Text(
            text = "Lorem ipsum dolor sit amet. ".repeat(20),
            modifier = Modifier.background(color2)
        )
    }
}

Запись экрана:

Это именно то, что я искал. Спасибо 😊

Argus Waikhom 13.07.2024 19:57

Другие вопросы по теме