1

I have an app, which represent a screen with bottom bar with 4 tabs. I use compose navigation with bottom bar. When user clicks on the bar the screen appears. How can I handle the situation when user clicks on the bar button for the 2-nd time, I need to listen to this event from the current inner screen and scroll the content up or do something else.

I investigate that I should use currentBackStackEntryAsState, but I am not sure which way.

1 Answer 1

1

You can build classes shared in your compose tree with staticCompositionLocalOf.

For this purpose I've build CurrentTabClickHandler - it's API is similar to BackHandler:

@Composable
fun CurrentTabClickHandler(
    enabled: Boolean = true,
    onTabClick: suspend () -> Unit,
) {
    val currentOnTabClick by rememberUpdatedState(onTabClick)
    val currentEnabled by rememberUpdatedState(enabled)
    val coroutineScope = rememberCoroutineScope()
    val handler = remember {
        CurrentTabClickDispatcher.Handler {
            if (currentEnabled) {
                coroutineScope.launch {
                    currentOnTabClick()
                }
            }
        }
    }
    val currentTabClickDispatcher = LocalCurrentTabClickDispatcher.current
    DisposableEffect(Unit) {
        currentTabClickDispatcher.addHandler(handler)
        onDispose {
            currentTabClickDispatcher.removeHandler(handler)
        }
    }
}

class CurrentTabClickDispatcher {
    class Handler(val action: () -> Unit)

    private val handlers = mutableListOf<Handler>()

    fun addHandler(handler: Handler) {
        handlers.add(handler)
    }

    fun removeHandler(handler: Handler) {
        handlers.remove(handler)
    }

    fun currentHandler() =
        handlers.lastOrNull()
}

val LocalCurrentTabClickDispatcher = staticCompositionLocalOf {
    CurrentTabClickDispatcher()
}

So in the screen you use it like this:

CurrentTabClickHandler {
    // to your action
}    

And to perform this action add this code to BottomNavigationItem:

val currentTabClickDispatcher = LocalCurrentTabClickDispatcher.current
BottomNavigationItem(
    // ...
    selected = isCurrent,
    onClick = {
        if (isCurrent) {
            when (val handler = currentTabClickDispatcher.currentHandler()) {
                null -> {
                    // no action is specified - I pop to initial tab screen here
                }
                else -> handler.action()
            }
        } else {
            // change tab
        }
    },
Sign up to request clarification or add additional context in comments.

4 Comments

thank you so much, could you please give an advise what to read to learn how to create such things like dispatchers
@Foenix you're welcome. I don't read, I lear from source codes. This one is inspired by BackHandler
where you use it CurrentTabClickHandler? I'm confused it
@ReinaldoRiantKurniaPerdana it should be placed inside a screen view where you expect to handle tab click

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.