Создание мультиплатформенной навигации Voyager с помощью ImagePicker

Я смотрел это руководство и мне было интересно, есть ли способ отправить параметры из приложения на экран Voyager, и если да, то как? Или как-то совместить эту ImagePicker реализацию с нижней навигацией?

Я пробовал много вещей, но на самом деле ничего не помогало: либо пустой экран, либо вылет с сообщением

java.lang.RuntimeException: Parcelable обнаружил исключение IOException, записывающее сериализуемый объект

Код:

actual class ImagePickerFactory {

    @Composable
    actual fun createPicker(): ImagePicker {
        val activity = LocalContext.current as ComponentActivity
        return remember(activity) { ImagePicker(activity) }
    }
}

actual class ImagePicker(private val activity: ComponentActivity) {

    private lateinit var getContent: ActivityResultLauncher<String>

    @Composable
    actual fun RegisterPicker(onImagePicked: (ByteArray) -> Unit) {
        getContent =
            rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri ->
                uri?.let {
                    activity.contentResolver.openInputStream(uri)?.use {
                        onImagePicked(it.readBytes())
                    }
                }
            }
    }

    actual fun ShowImagePicker() {
        getContent.launch("image/*")
    }
}

Это мои классы выбора изображений на стороне Android. Общий код выглядит следующим образом:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            App(ImagePickerFactory().createPicker())
        }
    }
}

@Composable
@Preview
fun App(imagePicker: ImagePicker) {
    initKoin()

    MaterialTheme {
        TabNavigator(
            tab = HomeTab
        ) {
            Scaffold(
                modifier = Modifier.fillMaxSize(),
                bottomBar = {
                    BottomNavigation(
                        backgroundColor = Color(0xFF3F54BE)
                    ) {
                        TabNavigationItem(HomeTab)
                        TabNavigationItem(SearchTab)
                        TabNavigationItem(ProfileTab(imagePicker))
                    }
                },
                content = { CurrentTab() }
            )
        }
    }
}

@Composable
private fun RowScope.TabNavigationItem(tab: Tab) {
    val tabNavigator: TabNavigator = LocalTabNavigator.current

    BottomNavigationItem(
        modifier = Modifier.padding(top = 24.dp),
        selected = tabNavigator.current == tab,
        onClick = { tabNavigator.current = tab },
        icon = {
            tab.options.icon?.let { icon ->
                Icon(
                    painter = icon,
                    contentDescription = null,
                    tint = if (tabNavigator.current == tab) Color.White else Color.Gray
                )
            }
        },
        label = {
            Text(text = tab.options.title)
        }
    )
}

data class ProfileTab(private val imagePicker: ImagePicker) : Tab {

    @Composable
    override fun Content() {
        Navigator(screen = ProfileScreen(imagePicker)) { navigator ->
            SlideTransition(navigator = navigator)
        }
    }

    override val options: TabOptions
        @Composable
        get() {
            val index: UShort = 2u

            return TabOptions(
                icon = rememberVectorPainter(Icons.Default.Person),
                index = index,
                title = ""
            )
        }
}

class ProfileScreen(private val imagePicker: ImagePicker) : Screen {
    @Composable
    override fun Content() {
        val viewModel = getScreenModel<ProfileViewModel>()
        imagePicker.RegisterPicker { imageBytes -> viewModel.saveUserImage(imageBytes) }
        ProfileScreenRoot(viewModel) { imagePicker.ShowImagePicker() }
    }
}

@Composable
fun ProfileScreenRoot(viewModel: ProfileViewModel, onImagePicked: () -> Unit) {
  //code unrelated to this issue
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
141
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я предполагаю, что это только на Android, исключением является исключение Java, похоже, что это сбой сериализации, который возникает, когда экраны не определены должным образом. В Voyager встроено восстановление состояния с использованием Java Serializable. Возможно, один из параметров вашего экрана не соответствует Java Serializable, и это является причиной сбоя.

Ознакомьтесь с документацией о том, как правильно определить экраны, соответствующие ретарации/сериализации состояния https://voyager.adriel.cafe/state-restoration/

Спасибо за ответ! Я думаю, это потому, что я пытался передать ImagePicker в качестве аргумента ProfileTab, и мне нужно было это сделать, потому что ImagePicker нужен контекст на Android, чтобы он мог работать. Я опубликую код здесь, в моем комментарии выше. Если у вас есть идеи, как найти обходной путь для его прохождения, поделитесь своими мыслями!

Naum Djordjevic 11.06.2024 03:07
Ответ принят как подходящий

В конечном итоге я «исправил» это, заменив ImagePicker этой классной библиотекой, которая используется как для Android, так и для iOS, под названием peekaboo. Это довольно просто и аккуратно, я рекомендую использовать его вместо реализации средства выбора изображений отдельно на обеих платформах, потому что это намного проще, и вы не столкнетесь с такими проблемами, как необходимость передачи контекста на стороне Android для создания фабрики выбора изображений, передачи его в экраны из приложения и т. д.

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