Как сделать @Preview в Jetpack Compose, когда компонент зависит от некоторых данных, предоставленных ViewModelAndroid

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Гость
 Как сделать @Preview в Jetpack Compose, когда компонент зависит от некоторых данных, предоставленных ViewModel

Сообщение Гость »


Я разрабатывал приложение, в котором пытаюсь реализовать некоторые новые технологии, например Jetpack Compose. И в целом, это отличный инструмент, за исключением того факта, что он имеет жесткую систему предварительной визуализации (@Preview), чем обычные XML-файлы дизайна.

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

В моем случае я сделал это:

@Preview( имя ="ListScreenPreview", showSystemUi = правда, шоубакграунд = правда, устройство = Устройства.NEXUS_9) @Композитный весело myPokemonRowPreview( @PreviewParameter(PokemonListScreenProvider::class) pokemonMokData: PokedexListModel ) { PokedexEntry( модель = pokemonMokData, navController = запомнитьNavController(), ViewModel = hiltViewModel()) } класс PokemonListScreenProvider: PreviewParameterProvider { переопределить значения val: Sequence =sequenceOf( PokedexListModel( pokemonName = "Какамон", число = 0, imageUrl = "https://raw.githubusercontent.com/PokeA ... emon/2.png" ), PokedexListModel( pokemonName = "Тонтаро", число = 73, imageUrl = "https://raw.githubusercontent.com/PokeA ... emon/1.png" ) ) } Чтобы представить этот @Composable:
@Композитный забавный PokemonListScreen( навконтроллер: Навконтроллер, Модель просмотра: PokemonListViewModel ) { Поверхность( цвет = MaterialTheme.colors.background, модификатор = Модификатор.fillMaxSize() ) { Столбец { Spacer(модификатор = Modifier.height(20.dp)) Изображение( художник = PainterResource (id = R.drawable.ic_international_pok_mon_logo), contentDescription = "Покемон", модификатор = Модификатор .fillMaxWidth() .align(По центру по горизонтали) ) Панель поиска( подсказка = "Искать...", модификатор = Модификатор .fillMaxWidth() .padding(16.dp) ) { viewModel.searchPokemonList(оно) } Spacer(модификатор = Modifier.height(16.dp)) PokemonList(navController = navController, модель просмотра = модель просмотра) } } } @Композитный забавный SearchBar( модификатор: Модификатор = Модификатор, подсказка: строка = " ", onSearch: (String) -> Unit = { } ) { вар текст, помните { mutableStateOf("") } var isHintDisplayed, запомнив { mutableStateOf(подсказка!= "") } Коробка (модификатор = модификатор) { BasicTextField(значение = текст, onValueChange = { текст = оно onSearch (оно) }, Макслинес = 1, одиночная линия = правда, textStyle = TextStyle(color = Color.Black), модификатор = Модификатор .fillMaxWidth() .shadow(5.dp, CircleShape) .background(Color.White, CircleShape) .padding(по горизонтали = 20.dp, по вертикали = 12.dp) .onFocusChanged { isHintDisplayed = !it.isFocused } ) если (isHintDisplayed) { Текст( текст = подсказка, цвет = Цвет.СветлыйСерый, модификатор = Модификатор .padding(по горизонтали = 20.dp, по вертикали = 12.dp) ) } } } @Композитный забавный список покемонов( навконтроллер: Навконтроллер, Модель просмотра: PokemonListViewModel ) { val pokemonList по памяти {viewModel.pokemonList} val endReached, запомнив {viewModel.endReached} val loadError, запомнив {viewModel.loadError} val isLoading, запомнив {viewModel.isLoading} val isSearching, запомнив {viewModel.isSearching} LazyColumn(contentPadding = PaddingValues(16.dp)) { val itemCount = if (pokemonList.size % 2 == 0) { pokemonList.size/2 } еще { pokemonList.size/2 + 1 } предметы (itemCount) { if (it >= itemCount - 1 && !endReached && !isLoading && !isSearching) { viewModel.loadPokemonPaginated() } PokedexRow(rowIndex = it, models = pokemonList, navController = navController, viewModel = viewModel) } } Коробка( contentAlignment = Центр, модификатор = Модификатор.fillMaxSize() ) { если (isLoading) { CircularProgressIndicator (цвет = MaterialTheme.colors.primary) } если (loadError.isNotEmpty()) { RetrySection (ошибка = loadError) { viewModel.loadPokemonPaginated() } } } } @SuppressLint("LogNotTimber") @Композитный весело PokedexEntry( модель: PokedexListModel, навконтроллер: Навконтроллер, модификатор: Модификатор = Модификатор, Модель просмотра: PokemonListViewModel ) { val defaultDominantColor = MaterialTheme.colors.surface var доминантный цвет, помните { mutableStateOf (по умолчаниюDominantColor) } Коробка( contentAlignment = Центр, модификатор = модификатор .shadow(5.dp, RoundedCornerShape(10.dp)) .clip(RoundedCornerShape(10.dp)) .aspectRatio(1f) .фон( Кисть.verticalGradient( listOf(dominantColor, defaultDominantColor) ) ) .кликабельный { navController.navigate( "pokemon_detail_screen/${dominantColor.toArgb()}/${model.pokemonName}/${model.number}" ) } ) { Столбец { CoilImage( imageRequest = ImageRequest.Builder(LocalContext.current) .data(model.imageUrl) .цель { viewModel.calcDominantColor(it) { цвет -> доминирующийЦвет = цвет } }.строить(), imageLoader = ImageLoader.Builder(LocalContext.current) .availableMemoryPercentage(0,25) .crossfade(истина) .строить(), contentDescription = model.pokemonName, модификатор = Модификатор .size(120.dp) .align(По центру по горизонтали), загрузка = { ОграничениеLayout( модификатор = Модификатор.fillMaxSize() ) { индикатор val = createRef() ЦиркулярПрогрессИндикатор( //Динамически устанавливаем ограничения модификатор = Modifier.constrainAs(индикатор) { top.linkTo(parent.top) дно.linkTo(родитель.дно) start.linkTo(родительский.start) end.linkTo(родительский.конец) } ) } }, // показывает текстовое сообщение об ошибке, если запрос не выполнен. неудача = { Text(text = «Запрос изображения не выполнен.») } ) Log.d("pokemonlist", model.imageUrl) Текст( текст = model.pokemonName, FontFamily = RobotoCondensed, размер шрифта = 20.sp, textAlign = TextAlign.Центр, модификатор = Modifier.fillMaxWidth(), ) } } } @Композитный весело PokedexRow( индекс строки: Целое, модели: List
, навконтроллер: Навконтроллер, Модель просмотра: PokemonListViewModel ) { Столбец { Ряд { PokedexEntry( модель = модели[rowIndex * 2], navController = navController, модификатор = Modifier.weight(1f), Модель просмотра = Модель просмотра ) Spacer(модификатор = Modifier.width(16.dp)) if (models.size >= rowIndex * 2 + 2) { PokedexEntry( модель = модели[rowIndex * 2 + 1], navController = navController, модификатор = Modifier.weight(1f), Модель просмотра = Модель просмотра ) } еще { Spacer(модификатор = Modifier.weight(1f)) } } Spacer(модификатор = Modifier.height(16.dp)) } } @Композитный весело RetrySection( ошибка: строка, onRetry: () -> Единица, ) { Столбец() { Текст (ошибка, цвет = Color.Red, fontSize = 18.sp) Spacer(модификатор = Modifier.height(8.dp)) Кнопка( onClick = { onRetry() }, модификатор = Modifier.align(По центру по горизонтали) ) { Текст (текст = «Повторить») } } } Я пытаюсь комментировать с помощью @Nullable navController и модели представления PokemonListScreen @Composable, но тоже не работает. Я все еще вижу пустой экран:


Изображение


Поэтому я пытаюсь поискать в документации Jetpack, но она просто определяет довольно простые Composables.

Так что, если у вас есть дополнительные сведения об этом и вы можете помочь, заранее спасибо!

Основная проблема заключается в том, что если я хочу просмотреть этот @Composable, хотя я сделал @Nullable для параметра viewmodel, и в этом, я думаю, проблема, AS все равно требует инициализации. Потому что я думаю, что правильный способ передать аргумент для предварительного просмотра — это аннотация @PreviewArgument.

[РЕДАКТИРОВАТЬ]

Покопавшись, я обнаружил, что AS возвращает следующую ошибку на экране предварительного просмотра:


Изображение


Итак, можно ли избежать ошибки модели представления??

[РЕШЕНИЕ]

Наконец, примените следующее решение, которое работает, поскольку причина проблемы связана с тем, что Hilt имеет некоторые несовместимости с предварительным просмотром Jetpack Compose:
[*]Создайте интерфейс вашей модели представления, который восстанавливает все переменные и методы. [*]Сделайте текущий класс модели расширения интерфейса. [*]Создайте класс 2º, расширяющий интерфейс, и передайте его в @Preview. @SuppressLint("UnrememberedMutableState") @Предварительный просмотр( name="ListScreenPreview", showSystemUi = правда, шоубакграунд = правда, устройство = Устройства.ПИКСЕЛЬ) @Композитный весело MyPokemonRowPreview( @PreviewParameter(PokemonListScreenProvider::class) pokemonMokData: PokedexListModel ) { JetpackComposePokedexTheme { PokedexRow( индекс строки = 0, модели = PokemonListScreenProvider().values.toList(), navController = запомнитьNavController(), viewModel = PokemonListViewModelMock( 0, mutableStateOf(""), mutableStateOf(значение = false), mutableStateOf (false), mutableStateOf (listOf (pokemonMokData)) ) ) } } класс PokemonListScreenProvider: PreviewParameterProvider
{ переопределить значения val: Sequence =sequenceOf( PokedexListModel( pokemonName = "Мачасаурио", число = 0, imageUrl = "https://raw.githubusercontent.com/PokeA ... emon/2.png" ), PokedexListModel( pokemonName = "Тонтаро", число = 73, imageUrl = "https://raw.githubusercontent.com/PokeA ... emon/1.png" ) ) } PokemonListViewModelInterface

интерфейс PokemonListViewModelInterface { вар curPage: Int var loadError: MutableState var isLoading: MutableState var endReached: MutableState var pokemonList: MutableState интересный поискPokemonList (запрос: String) забавная загрузкаPokemonPaginated() fun CalcDominantColor (drawable: Drawable, onFinish: (Color) -> Unit) } PokemonListViewModelMock

класс PokemonListViewModelMock ( переопределить var curPage: Int, переопределить var loadError: MutableState, переопределить переменную isLoading: MutableState, переопределить var endReached: MutableState, переопределить var pokemonList: MutableState ): PokemonListViewModelInterface{ переопределить fun searchPokemonList(query: String) { TODO("Еще не реализовано") } переопределить удовольствие loadPokemonPaginated() { TODO("Еще не реализовано") } переопределить funcalcDominantColor(drawable: Drawable, onFinish: (Color) -> Unit) { TODO("Еще не реализовано") } } Фактический предварительный просмотр выглядит следующим образом, и хотя изображение не отображается, оно отображается правильно:


Изображение

Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Функциональность Sympy.solve зависит от предоставленных коэффициентов
    Anonymous » » в форуме Python
    0 Ответы
    24 Просмотры
    Последнее сообщение Anonymous
  • Функциональность Sympy.solve зависит от предоставленных коэффициентов
    Anonymous » » в форуме Python
    0 Ответы
    16 Просмотры
    Последнее сообщение Anonymous
  • Завершение оболочки зависит от уже предоставленных аргументов
    Anonymous » » в форуме Python
    0 Ответы
    7 Просмотры
    Последнее сообщение Anonymous
  • Как правильно переходить из ViewModel в Jetpack Compose + Hilt + ViewModel?
    Anonymous » » в форуме Android
    0 Ответы
    36 Просмотры
    Последнее сообщение Anonymous
  • Как вычислять Windowsizeclass в JetPack Compose @preview
    Anonymous » » в форуме Android
    0 Ответы
    4 Просмотры
    Последнее сообщение Anonymous

Вернуться в «Android»