voyager icon indicating copy to clipboard operation
voyager copied to clipboard

Support dynamic icons when working with tabs

Open mainrs opened this issue 1 year ago • 6 comments

It would be nice to have some sort of selected property available that allows one to dynamically select an icons if the current tab has focus or not.

@Composable
override val options: TabOptions
    get() = TabOptions(index = 0u, title = "Home", icon = if (selected) Icons.Filled.Home else Icons.Default.Home)

mainrs avatar Jan 21 '24 00:01 mainrs

I guess a good solution for this would be to extend TabOptions to support two icons: selectedIcon and unselectedIcon. And have the user decide what to do with them.

mainrs avatar Jan 21 '24 01:01 mainrs

A workaround is possible right now, but native support would be cleaner:

interface NiceTab : Tab {
    val niceTabOptions: NiceTabOptions
        @Composable get

    override val options: TabOptions
        @Composable get() {
            val index = niceTabOptions.index
            val title = niceTabOptions.title

            return remember {
                TabOptions(
                    index = index,
                    title = title,
                    icon = null
                )
            }
        }
}

data class NiceTabOptions(
    val index: UShort,
    val title: String,
    val selectedIcon: Painter? = null,
    val unselectedIcon: Painter? = null,
)

object HomeTab : NiceTab {
    override val niceTabOptions: NiceTabOptions
        @Composable get() {
            val selectedIcon = rememberVectorPainter(Icons.Filled.Home)
            val unselectedIcon = rememberVectorPainter(Icons.Outlined.Home)

            return remember {
                NiceTabOptions(
                    index = 0u,
                    title = "Home",
                    selectedIcon = selectedIcon,
                    unselectedIcon = unselectedIcon,
                )
            }
        }
}

@Composable
private fun RowScope.TabNavigationItem(tab: NiceTab) {
    val tabNavigator = LocalTabNavigator.current
    val selected = tabNavigator.current == tab
    val icon = if (selected) tab.niceTabOptions.selectedIcon else tab.niceOptions.unselectedIcon

    BottomNavigationItem(
        selected = selected,
        onClick = { tabNavigator.current = tab },
        icon = { icon?.let { icon -> Icon(painter = icon, contentDescription = tab.title) } }
    )
}

mainrs avatar Jan 21 '24 01:01 mainrs

Related to https://github.com/adrielcafe/voyager/issues/141

Syer10 avatar Jan 21 '24 01:01 Syer10

In navigation library should not be any UI related things, that force developer to declare them especially when they are not going to be used. What if I don't want unselected icon or selected or even title. What if I want tab option that declare unselectedTitle and so on. No one would be happy in all cases. In my opinion if tab options can not be deprecated as concept at all, there should be left only 'index'.

Velord avatar Jan 21 '24 22:01 Velord

Greetings, any updates / plans on this one? I don't want this to look like a complaint (it's not), I mean, it's OSS and folks are putting great effort into the project, but imo this UI limitation greatly devalues the tab navigator feature as a whole because what app would want to use the same icons for active and inactive tabs? Actually I'm a bit surprised this hasn't gained more traction, are there any workarounds, perhaps more elegant than the one suggested by @mainrs , that I'm not aware of?

vad-zuev avatar Jul 17 '24 07:07 vad-zuev

It's still a small workaround for a feature that not every app actually wants. And the workaround is easy to remove once the feature lands. I think there are discussions about making the data generic, so everybody can do with it whatever they want. As of right now, there is no better solution afaik.

mainrs avatar Jul 17 '24 09:07 mainrs