Я реализую экран выбора темы для своего приложения. Идея состоит в том, чтобы предоставить пользователю различные темы, из которых он может выбирать, и отобразить предварительный просмотр двух экранов, чтобы пользователь мог видеть, как будет выглядеть тема после ее выбора.
Я показываю этот главный экран в качестве предварительного просмотра:
Вот как выглядит мой экран выбора темы:
Я хочу уменьшить содержимое главного экрана, чтобы отобразить все содержимое главного экрана в доступной области предварительного просмотра выбора темы.
Я пробовал использовать 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?
Я попробовал то, что @Leviathan предложил в комментарии. Это работает, но из-за этого сложно возложить ответственность на пользовательский интерфейс. Мой текущий пользовательский интерфейс выглядит примерно так
Теперь мне нужно переместить содержимое строки наружу
После уменьшения масштаба оба предварительного просмотра будут в центре, и мне нужно указать смещения по x и y в том месте, где я хочу.
Проблема с этим методом заключается в том, что, поскольку поле предварительного просмотра привязано к родительскому элементу, выравнивание может быть отключено в зависимости от измерения пользовательского устройства.
взгляните на макет BoxWithConstraints, такой же, как у box, с возможностью установки минимальной и максимальной ширины и высоты: foso.github.io/Jetpack-Compose-Playground/foundation/layout/…
@Leviathan Только что попробовал это решение. Это работает, но из-за этого сложно возложить ответственность на пользовательский интерфейс. Мой текущий пользовательский интерфейс выглядит примерно так: Столбец - Строка - Вес поля 1f - Вес поля 1f - Остальная часть пользовательского интерфейса Теперь мне нужно переместить содержимое строки наружу - Поле - Столбец - Пустое поле веса 1f - Остальная часть пользовательского интерфейса - Предварительный просмотр слева в поле - Предварительный просмотр справа После уменьшения масштаба оба предварительного просмотра будут в центре, и мне нужно указать смещения по осям x и y в том месте, где я хочу, чтобы они были. Когда я тестировал это на экранах разных размеров, выравнивание было немного неправильным в зависимости от устройства.
Попробуйте добавить собственный 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)
)
}
}
Запись экрана:
Это именно то, что я искал. Спасибо 😊
Что произойдет, если вы нарисуете предварительный просмотр в полном размере, занимая весь экран, а затем уменьшите его?