Home > Net >  While clicking on the tab with HorizontalPager in android Jetpack Compse, it jumps to the last tab
While clicking on the tab with HorizontalPager in android Jetpack Compse, it jumps to the last tab

Time:02-10

While clicking on the tab with HorizontalPager in android Jetpack Compse, it jumps to the last tab I add the code to see the problem visible

This is my code ->

data class TabPage(val title: String?, val icon: ImageVector? = null, var screen: (@Composable () -> Unit)? = null)

@OptIn(ExperimentalPagerApi::class)
@Composable
fun SwipeableTabLayout(
    modifier: Modifier = Modifier,
    tabPages: List<TabPage>,
    scrollable: Boolean = false,
    isIconTab: Boolean = false,
    unselectedContentColor: Color = MaterialTheme.colors.textColorTertiary,
    tabBackgroundColor: Color = MaterialTheme.colors.surface,
    tabContentColor: Color = MaterialTheme.colors.primary,
    backgroundColor: Color = MaterialTheme.colors.surface
) {
    val pagerState = rememberPagerState()
    val scope = rememberCoroutineScope()
    Surface(color = backgroundColor) {
        Column {
            if (scrollable) {
                ScrollableTab(
                    modifier = modifier,
                    tabPages = tabPages,
                    selectedTabIndex = pagerState.currentPage,
                    onSelectedTab = { scope.launch { pagerState.animateScrollToPage(tabPages.indexOf(it)) } },
                    isIconTab = isIconTab,
                    unselectedContentColor = unselectedContentColor,
                    backgroundColor = tabBackgroundColor,
                    contentColor = tabContentColor
                )
            } else {
                FixedTab(
                    modifier = modifier,
                    tabPages = tabPages,
                    selectedTabIndex = pagerState.currentPage,
                    onSelectedTab = { scope.launch { pagerState.animateScrollToPage(tabPages.indexOf(it)) } },
                    isIconTab = isIconTab,
                    unselectedContentColor = unselectedContentColor,
                    backgroundColor = tabBackgroundColor,
                    contentColor = tabContentColor
                )
            }

            HorizontalPager(
                state = pagerState,
                count = tabPages.size,
                content = { page -> tabPages[page].screen?.invoke() })
        }
    }
}

@Composable
fun ScrollableTab(
    modifier: Modifier = Modifier,
    tabPages: List<TabPage>,
    selectedTabIndex: Int,
    isIconTab: Boolean = false,
    unselectedContentColor: Color,
    backgroundColor: Color,
    contentColor: Color,
    onSelectedTab: (TabPage) -> Unit
) {
    ScrollableTabRow(
        modifier = modifier,
        edgePadding = 0.dp,
        selectedTabIndex = selectedTabIndex,
        backgroundColor = backgroundColor,
        contentColor = contentColor
    ) {
        tabPages.forEachIndexed { index, tabPage ->
            if (isIconTab) {
                LeadingIconTab(
                    selected = index == selectedTabIndex,
                    unselectedContentColor = unselectedContentColor,
                    onClick = { onSelectedTab(tabPage) },
                    text = { Text(text = tabPage.title ?: "") },
                    icon = tabPage.icon?.let { icon -> { Icon(imageVector = icon, contentDescription = null) } } ?: {}
                )
            } else {
                Tab(
                    selected = index == selectedTabIndex,
                    unselectedContentColor = unselectedContentColor,
                    onClick = { onSelectedTab(tabPage) },
                    text = { Text(text = tabPage.title ?: "") },
                    icon = tabPage.icon?.let { icon -> { Icon(imageVector = icon, contentDescription = null) } }
                )
            }
        }
    }
}

@Composable
fun FixedTab(
    modifier: Modifier = Modifier,
    tabPages: List<TabPage>,
    selectedTabIndex: Int,
    isIconTab: Boolean = false,
    unselectedContentColor: Color = MaterialTheme.colors.textColorTertiary,
    backgroundColor: Color,
    contentColor: Color,
    onSelectedTab: (TabPage) -> Unit
) {
    TabRow(selectedTabIndex = selectedTabIndex, backgroundColor = backgroundColor, contentColor = contentColor) {
        tabPages.forEachIndexed { index, tabPage ->
            if (isIconTab) {
                LeadingIconTab(
                    modifier = modifier,
                    selected = index == selectedTabIndex,
                    unselectedContentColor = unselectedContentColor,
                    onClick = { onSelectedTab(tabPage) },
                    text = { Text(text = tabPage.title ?: "") },
                    icon = tabPage.icon?.let { icon -> { Icon(imageVector = icon, contentDescription = null) } } ?: {}
                )
            } else {
                Tab(
                    modifier = modifier,
                    selected = index == selectedTabIndex,
                    unselectedContentColor = unselectedContentColor,
                    onClick = { onSelectedTab(tabPage) },
                    text = tabPage.title?.let { title -> { Text(text = title) } },
                    icon = tabPage.icon?.let { icon -> { Icon(imageVector = icon, contentDescription = null) } }
                )
            }
        }
    }
}


And this is where it is used ->

    val tabPages = listOf(
        TabPage(title = SnackbarType.ERROR.value, screen = { LoadScreen(SnackbarType.ERROR) }),
        TabPage(title = SnackbarType.WARNING.value, screen = { LoadScreen(SnackbarType.WARNING) }),
        TabPage(title = SnackbarType.SUCCESS.value, screen = { LoadScreen(SnackbarType.SUCCESS) }),
        TabPage(title = SnackbarType.INFO.value, screen = { LoadScreen(SnackbarType.INFO) })
    )

    Scaffold(
        backgroundColor = MaterialTheme.colors.background,
        topBar = {
            CatalogTopAppBar(
                title = stringResource(id = R.string.snackbar),
                subtitle = stringResource(id = R.string.core_components),
                navigateUp = { onNavigate(Destination.Up) },
            )
        },
        content = {
            SwipeableTabLayout(tabPages = tabPages, scrollable = true)
        }
    )

@Composable
private fun LoadScreen(snackbarType: SnackbarType) {
    val scaffoldState = rememberScaffoldState()
    val scope = rememberCoroutineScope()

    Column(
        modifier = Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState())
            .padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(16.dp),
    ) {

        Text(text = "One line", style = MaterialTheme.typography.payback.headline6, color = MaterialTheme.colors.onSurface)
        LoadSnackbar(message = stringResource(R.string.snackbar_1_line_message_text), snackbarType = snackbarType)

        Text(text = "Two lines", style = MaterialTheme.typography.payback.headline6, color = MaterialTheme.colors.onSurface)
        LoadSnackbar(message = stringResource(R.string.snackbar_2_lines_message_text), maxLine = 2, snackbarType = snackbarType)

        Text(text = "One line with action", style = MaterialTheme.typography.payback.headline6, color = MaterialTheme.colors.onSurface)
        LoadSnackbar(
            message = stringResource(R.string.snackbar_1_line_message_text),
            snackbarType = snackbarType,
            actionLabel = "Action"
        )

        Text(text = "Two lines with action", style = MaterialTheme.typography.payback.headline6, color = MaterialTheme.colors.onSurface)
        LoadSnackbar(
            message = stringResource(R.string.snackbar_2_lines_message_text),
            snackbarType = snackbarType,
            actionLabel = "Action",
            maxLine = 2
        )

        val oneLineMessage = stringResource(R.string.snackbar_1_line_message_text)
        ContainedButton(
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = dimensionResource(R.dimen.ds_spacing_06)),
            text = "Show 1 line Snackbar",
            onClick = {
                scope.launch {
                    scaffoldState.snackbarHostState.showSnackbar(message = oneLineMessage, duration = SnackbarDuration.Short)
                }
            },
        )

        val twoLineMessage = stringResource(R.string.snackbar_2_lines_message_text)
        ContainedButton(
            modifier = Modifier.fillMaxWidth(),
            text = "Show 2 lines Snackbar",
            onClick = {
                scope.launch {
                    scaffoldState.snackbarHostState.showSnackbar(message = twoLineMessage, duration = SnackbarDuration.Short)
                }
            },
        )
    }

    Box(modifier = Modifier.fillMaxSize()) {
        SnackbarSetting(
            snackbarHostState = scaffoldState.snackbarHostState,
            snackbarType = snackbarType,
            maxLine = 2,
            modifier = Modifier.align(Alignment.BottomCenter)
        )
    }
}

If the LoadScreen() function just loads a simple text, it works well but when you add more items, while clicking it jumps to the last tab

e.g. with this LoadScreen() works fine ->

@Composable
private fun LoadScreen(snackbarType: SnackbarType) {
    val scaffoldState = rememberScaffoldState()

    Column(
        modifier = Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState())
            .padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(16.dp),
    ) {

        Text(text = "One line", style = MaterialTheme.typography.payback.headline6, color = MaterialTheme.colors.onSurface)
        LoadSnackbar(message = stringResource(R.string.snackbar_1_line_message_text), snackbarType = snackbarType)

    }

    Box(modifier = Modifier.fillMaxSize()) {
        SnackbarSetting(
            snackbarHostState = scaffoldState.snackbarHostState,
            snackbarType = snackbarType,
            maxLine = 2,
            modifier = Modifier.align(Alignment.BottomCenter)
        )

CodePudding user response:

  •  Tags:  
  • Related