Android Jetpack Compose — Navigation

Android Jetpack Compose — Navigation - Coletiv blog

If you’re an Android developer you’ve probably heard about Compose already. It’s everywhere, and it’s nice to see the Android community so excited about it. For the ones that haven’t heard about it already, Compose is Android’s modern toolkit for building native UI that hopes to simplify and accelerate UI development on Android. It’s all in Kotlin so you can forget about writing UI code on XML, and that alone is something to be excited for 😄. Check the official page and try it out if you haven’t already.

But enough of chit-chat and let’s get on the topic because that’s what you’re here for.

How to handle navigation on Compose

As you might know already, there’s no official way of doing navigation with Compose, if you want to go full Compose you need to handle it yourself and that’s a pain 🔨.

You can’t do an app with Compose without using a least one Activity (at least for now) so let’s use this to our advantage and use the Navigation jetpack component, it has a lot of nice features and is the current official recommended way of handling navigation on Android apps. Let’s check how we can do this.

Using the Navigation component

Telling you how to get started with the Navigation component is out of the scope of this article but you can follow the official getting started tutorial.

I’m assuming that you have your MainActivity setup alongside a start destination fragment.

The layout file of your MainActivity should look like this:

<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/host_fragment_container"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:navGraph="@navigation/nav_graph"
    tools:context=".ui.screens.MainActivity" />

That’s the only layout file we need. I promise 😅.

You can delete your fragment layout file and update the code to this:

class SomeFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? = ComposeView(requireContext()).apply {
        setContent {
            AwesomeComposable()
        }
    }

    @Composable
    fun AwesomeComposable() {
        ...
    }
}

This is where the magic happens. We’re telling our fragment that we want to use a ComposeView and we’re calling setContent to set our Compose UI. No need for layout files or other views 👍.

Then you just need to create more fragments like this one and add them to your nav_graph.xml file as destinations.

Now you should be able to navigate to those destinations inside your composable functions by calling:

findNavController().navigate(R.id.your_action_here)

You can improve this further by creating a base fragment class like this:

abstract class ComposeFragment : Fragment() {
    @Composable
    abstract fun ComposeContent()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? = ComposeView(requireContext()).apply {
        setContent { ComposeContent() }
    }
}

And use it on your fragments like this:

class SomeFragment : ComposeFragment() {
    @Composable
    override fun ComposeContent() {
        // your compose layout
    }
}

Neat! Now you can forget that you’re using fragments and focus on Compose to write some beautiful UI 🌠. Go crazy!

What if I want to go full Compose?

For the time being, you have 2 options that I’m aware of:

  • You can try to use the compose-router library that adds routing functionality to Jetpack Compose.
  • Write your navigation system. Be sure to check Jetpack Compose Samples for some examples on how to do this.

But I think that the best option at this time is to use the mature Navigation component like suggested here and wait until there’s an official way of handling navigation on Compose. Sure, you’ll be using fragments with ComposeView (which seems to be old/outdated comparing to Compose) but you’ll always have a MainActivity somewhere in your project to set the content of your composable functions, so might as well take some advantage of it.

Wouldn’t it be nice to have a main() function that would allow us to write our compose code right away? No Activity or Fragment needed? Let’s keep dreaming 😄!

Thank you for reading!

Thank you so much for reading, it means a lot to us! Also don’t forget to follow Coletiv on Twitter and LinkedIn as we keep posting more and more interesting articles on multiple technologies.

In case you don’t know, Coletiv is a software development studio from Porto specialised in Elixir, Web, and App (iOS & Android) development. But we do all kinds of stuff. We take care of UX/UI design, software development, and even security for you.

So, let’s craft something together?