Hazer / nav

A simple declarative Android compose navigator

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Nav

CircleCI Sonatype Snapshot

A simple declarative Android compose navigator

Nav

Usage

The core component is a Navigator that takes a list of pages. The top page will be displayed to the user and pages in the backstack will have their state saved. You can use anything to represent your page state, but I recommend using a sealed class. You should also use rememberSaveable() to ensure the pages are remembered through process death.

sealed class Page : Parcelable {
   @Parcelize
   object List : Page()
   @Parcelize
   data class Detail(id: Int): Page()
}

val pages = rememberSaveable { mutableStateListOf<Page>(Page.List) }

Navigator(pages = pages, onPopPage = { pages.removeLast() }) { page ->
   when (page) {
       is List -> ListPage()
       is Detail -> DetailPage(id = page.id)
   }
}

This allows you to control the back stack however you want. Alternatively, if you want a more opinionated way to manipulate the backstack you can use the BackStack class. If will enforce a starting destination and you can only push and pop the stack.

val backStack = rememberSaveable { backStackOf<Page>(Page.List) } 

Navigator(backStack) { page ->
   when (page) {
       is List -> ListPage()
       is Detail -> DetailPage(id = page.id)
   }
}

...

backStack.navigate(page = Page.Detail(id = 1)) {
  popUpTo(singleTop = true) { it is Page.List }
}
backStack.pop()

Router

Usage

You can annotate sealed class variants with @Route("path") and it will generate a parseRoute() method to parse a path into the correct variant.

sealed class Page : Parcelable {
   @Parcelize
   @Route("", root = true)
   object List : Page()
   @Parcelize
   @Route("/detail/{id}")
   data class Detail(id: Int): Page()
}
...

val backStack = backStackOf(parseRoute(deepLink))

A helper is also provided to route your deep link from your activity into your compose tree. It is recommend you set android:launchMode="singleTop" in your manifest and override onNewIntent(). This ensures your Activity isn't recreated when receiving an intent.

class MainActivity : ComponentActivity() {
    
    private val deepLinkHandler = DeepLinkHandler(this)

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

        setContent {
            var backStack by rememberSaveableOf { mutableStateOf(backStackOf<Page>(Page.Home)) }
            deepLinkHandler.OnDeepLink { link -> backStack = backStackOf(parseRoute(link)) }
            App(backStack)
        }
    }

    override fun onNewIntent(intent: Intent?) {
        deepLinkHandler.onNewIntent(intent)
    }
}

About

A simple declarative Android compose navigator


Languages

Language:Kotlin 100.0%