A small navigation library for Android to ease the use of fragment transactions & handling backstack (also available for Jetpack Compose).

Overview

navigator

build

Looking for Jetpack Compose implementation of navigator, see here.

A small (Kotlin first) navigation library for Android to ease the use of fragment transactions with a navigator.navigateTo call (rest is handled for you) & navigating back is as simple as navigator.goBack().

You also get a separate onBackPressed() callback on the child fragments which will be called when this is the current visible fragment & is the one which is going to be removed upon back press.

The library provides some custom transitions like CircularTransform (on top of existing animations), see its use in the sample app here.

If you have any implementation details to cover let me know.

What additional benefits I can get when using this library?

  • Proper handling of Fragment Transaction.
  • Handling up & back press actions efficiently on Fragment.
  • Easy to use API for animations & transitions (see here).
  • Generic Typed Arguments when passing data between destinations (see here).
  • Quick Bottom & Tab navigation setup (see tutorials).

Implementation

  • The individual library versions can be found here.
// root's build.gradle
allprojects {
    repositories {
        mavenCentral()
    }
}
" // Core library (Required) implementation "io.github.kaustubhpatange:navigator-extensions:" // Optional but recommended implementation "io.github.kaustubhpatange:navigator-bottom-navigation:" // For setting up Bottom Navigation. implementation "io.github.kaustubhpatange:navigator-tab-navigation:" // For setting up Tab Layout Navigation. implementation "io.github.kaustubhpatange:navigator-rail-navigation:" // For setting up Rail Navigation. } ">
// modules's build.gradle
dependencies {
    // Check the above link for the individual library versions.
    implementation "io.github.kaustubhpatange:navigator:" // Core library (Required)
    implementation "io.github.kaustubhpatange:navigator-extensions:" // Optional but recommended
    implementation "io.github.kaustubhpatange:navigator-bottom-navigation:" // For setting up Bottom Navigation.
    implementation "io.github.kaustubhpatange:navigator-tab-navigation:" // For setting up Tab Layout Navigation.
    implementation "io.github.kaustubhpatange:navigator-rail-navigation:" // For setting up Rail Navigation.
}

Samples

  • Basic sample - Hands on with the introduction to some library features.
  • Backpress sample - A sample focused on handling back press events effectively.
  • Navigation Sample - A sample which demonstrate the use of Bottom & Tab navigation supporting multiple backstack through navigator.
  • Running the samples

// Run the following command before building the project.

./gradlew navigator:publishReleasePublicationToMavenLocal

Tutorials

Apps using navigator

If you would like me to add your app in the list, let me know through issues.

Name
Moviesy - Client app for YTS movies
XClipper - Clipboard manager for Android & Windows

License

Copyright 2020 Kaustubh Patange

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • Feature request : Option to not add current route to backstack when navigating

    Feature request : Option to not add current route to backstack when navigating

    Something like noHistory : Boolean.

    For example for a welcome screen that should not be returned to after navigating to real content while still allowing a single root route and proper integrated animations when using that route.

    opened by Tolriq 42
  • Navigation Compose scoped view models

    Navigation Compose scoped view models

    Hi again :)

    So I'm trying to have scoped viewModels to screens with hilt and this is quite an headache due to the current hilt limitations.

    Do you have any plans to add support for something equivalent to hiltViewModel from compose navigation?

    opened by Tolriq 24
  • Bug: Default transitions does not work in release builds with R8

    Bug: Default transitions does not work in release builds with R8

    Due to https://github.com/KaustubhPatange/navigator/blob/master/navigator-compose/navigator-compose/src/main/java/com/kpstv/navigation/compose/ComposeNavigator.kt#L139 the default transitions do not work in release build.

    Harcoding a string key correctly fix the issue.

    opened by Tolriq 9
  • There are some problems when using the [FragmentNavigator.TransactionType.ADD], Why?

    There are some problems when using the [FragmentNavigator.TransactionType.ADD], Why?

    Hello, there are some problems here, as shown below:
    After using add, the expectation should be the show/hide operation of the fragment, right? But they overlap and can be clicked, why?

    image

    opened by xuexixuexijpg 6
  • [Navigator Compose] Nested navigation does not save saveables in `SaveableStateHolder` across process death.

    [Navigator Compose] Nested navigation does not save saveables in `SaveableStateHolder` across process death.

    While testing the sample app I encountered that the scroll state of LazyColumn is not restored across process death. It works when moved into the first navigator.Setup route.

    opened by KaustubhPatange 3
  • There is a problem with the example module

    There is a problem with the example module

    Hello, I used this library as a practice code. When I first saw it, I thought this library was very useful. Then I used the leakcanary memory leak detection tool to check some code of the example, here are some problems:

    multi-modlue-sample:

    Snipaste_2022-05-11_16-22-40 Snipaste_2022-05-11_16-25-51

    navigation-sample

    Snipaste_2022-05-11_16-40-12 Snipaste_2022-05-11_16-42-12

    Posted where the memory leaked and the modified code.The test is not complete, there may be undetected, only these two example modules are tested

    opened by xuexixuexijpg 2
  • Write Tests

    Write Tests

    This is to remind me that I must write tests when the API is stable or there will be no breaking change.

    I was thinking to write tests for the sample application & check if their behaviors are expected because testing each edge case with the navigator might take a lot of time. This maybe a good idea but will see!

    opened by KaustubhPatange 2
  • [Navigator Compose] Design of `singleTop` is different from traditional navigation system

    [Navigator Compose] Design of `singleTop` is different from traditional navigation system

    For a very long time, we knew how a single top instance worked in the Fragment's navigation world. Since transactions in the FragmentManager are reversible the only way to correctly achieve this functionality of singleTop is to pop the backstack up to the point where we find that respective instance in the FragmentTransaction. This is how navigator & Jetpack Navigation handles single top functionality.

    In Compose world, this could take a different turn since destinations are nothing but a State which we observe to switch between different composables we can remove it at any point without affecting the previous transaction (i.e history). The current implementation does not work like how it was done in Fragments world, here we just remove all the existing instances from the backstack directly (i.e no recursive pop till we find that instance).

    This could be confusing since the functionality is not carried over to the new system. Now should I keep or change the logic that we are familiar with Fragments? Changing it would then become a breaking change.

    help wanted 
    opened by KaustubhPatange 1
  • Should I expose the private methods of `ComposeNavigator` like `goBack` or `canGoBack`.

    Should I expose the private methods of `ComposeNavigator` like `goBack` or `canGoBack`.

    Apart from this, I'm also thinking to provide a new API for returning the snapshot of current navigation.

    This could be useful when handling back press using user-defined custom logic.

    help wanted 
    opened by KaustubhPatange 1
  • Fix: Proper lifecycle handling/creation on destination (navigator-compose)

    Fix: Proper lifecycle handling/creation on destination (navigator-compose)

    TODO:

    • ~Remove logs~
    • Find a better way to solve removeStateAndConfiguration(filterByCurrent = false) either exclude current destination when removing or keep using this.
    opened by KaustubhPatange 0
  • [Added] `current` & `parent` properties to `Controller<T>` class.

    [Added] `current` & `parent` properties to `Controller` class.

    These APIs are added to support navigation scoped ViewModels.

    current - The current active Route in the navigation history. parent - The parent Route associated with this nested navigation if it already is otherwise null.

    Additional Changes

    • Updated Gradle version
    opened by KaustubhPatange 0
  • Crash on Production app with IllegalStateException

    Crash on Production app with IllegalStateException

    @KaustubhPatange I am getting this crash on Live App, could you please take a look at this issue Thanks.

    Exception java.lang.IllegalStateException: Restarter must be created only during owner's initialization stage at androidx.savedstate.SavedStateRegistryController.performAttach (SavedStateRegistryController.kt:45) at androidx.savedstate.SavedStateRegistryController.performRestore (SavedStateRegistryController.kt:63) at com.lengo.uni.navigation.navigator_compose.LifecycleController.performRestore$app_allLangRelease (LifecycleController.java:206) at com.lengo.uni.navigation.navigator_compose.ComposeNavigator$Setup$1$1$1.invoke (ComposeNavigator.kt:1316) at com.lengo.uni.navigation.navigator_compose.ComposeNavigator$Setup$1$1$1.invoke (ComposeNavigator.kt:1310) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:116) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:34) at com.lengo.uni.navigation.navigator_compose.ComposeNavigator$CommonEffect$1$1$1.invoke (ComposeNavigator.kt:1401) at com.lengo.uni.navigation.navigator_compose.ComposeNavigator$CommonEffect$1$1$1.invoke (ComposeNavigator.kt:1390) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:116) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:34) at androidx.compose.foundation.layout.BoxWithConstraintsKt$BoxWithConstraints$1$1$measurables$1.invoke (BoxWithConstraints.kt:69) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:34) at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$2$1$1.invoke (SubcomposeLayout.kt:770) at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$2$1$1.invoke (SubcomposeLayout.kt:448) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke (ComposableLambda.jvm.kt:34) at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable (ActualJvm_jvmKt.java:74) at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke (Composer.kt:3193) at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke (Composer.kt:3183) at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations (SnapshotStateKt__DerivedStateKt.java:252) at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations (SnapshotStateKt.java:1) at androidx.compose.runtime.ComposerImpl.doCompose (Composer.kt:3183) at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release (ComposerImpl.java:3119) at androidx.compose.runtime.CompositionImpl.composeContent (Composition.kt:584) at androidx.compose.runtime.Recomposer.composeInitial$runtime_release (Recomposer.kt:811) at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release (Composer.kt:3712) at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release (Composer.kt:3712) at androidx.compose.runtime.CompositionImpl.setContent (Composition.kt:519) at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcomposeInto (SubcomposeLayout.kt:468) at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose (SubcomposeLayout.kt:441) at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose (SubcomposeLayout.kt:432) at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose (LayoutNodeSubcompositionsState.java:421) at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$Scope.subcompose (SubcomposeLayout.kt:732) at androidx.compose.foundation.layout.BoxWithConstraintsKt$BoxWithConstraints$1$1.invoke-0kLqBqw (BoxWithConstraints.kt:69) at androidx.compose.foundation.layout.BoxWithConstraintsKt$BoxWithConstraints$1$1.invoke (BoxWithConstraints.kt:67) at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s (SubcomposeLayout.kt:590) at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0 (InnerPlaceable.kt:44) at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke (LayoutNode.kt:1428) at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke (LayoutNode.kt:1427) at androidx.compose.runtime.snapshots.Snapshot$Companion.observe (Snapshot.kt:2116) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads (SnapshotStateObserver.kt:110) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release (OwnerSnapshotObserver.kt:78) at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release (OwnerSnapshotObserver.java:66) at androidx.compose.ui.node.LayoutNode.performMeasure-BRTryo0$ui_release (LayoutNode.java:1427) at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0 (OuterMeasurablePlaceable.kt:94) at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0 (OuterMeasurablePlaceable.kt:75) at androidx.compose.ui.node.LayoutNode.measure-BRTryo0 (LayoutNode.kt:1366) at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1.measure-3p2s80s (Box.kt:137) at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0 (InnerPlaceable.kt:44) at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke (LayoutNode.kt:1428) at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke (LayoutNode.kt:1427) at androidx.compose.runtime.snapshots.Snapshot$Companion.observe (Snapshot.kt:2116) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads (SnapshotStateObserver.kt:110) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release (OwnerSnapshotObserver.kt:78) at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release (OwnerSnapshotObserver.java:66) at androidx.compose.ui.node.LayoutNode.performMeasure-BRTryo0$ui_release (LayoutNode.java:1427) at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0 (OuterMeasurablePlaceable.kt:94) at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release (LayoutNode.java:1381) at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release$default (LayoutNode.java:1372) at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA (MeasureAndLayoutDelegate.kt:187) at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded (MeasureAndLayoutDelegate.kt:274) at androidx.compose.ui.node.MeasureAndLayoutDelegate.access$remeasureAndRelayoutIfNeeded (MeasureAndLayoutDelegate.kt:38) at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout (MeasureAndLayoutDelegate.kt:208) at androidx.compose.ui.platform.AndroidComposeView.measureAndLayout (AndroidComposeView.android.kt:757) at androidx.compose.ui.node.Owner.measureAndLayout$default (Owner.java:196) at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw (AndroidComposeView.android.kt:954) at android.view.View.draw (View.java:23190)

    opened by shakil807g 10
  • Access Argument in ViewModel for Navigator Compose

    Access Argument in ViewModel for Navigator Compose

    Is it possible to get Navigation arguments from SavedStateHandle in ViewModels like we can do in Navigation Compose library

    private val lectionName: String = savedStateHandle.get("lectionName")!!
    private val packName: String = savedStateHandle.get("packName")!!
    
    opened by shakil807g 1
Releases(nc-0.1-alpha09)
Owner
Kaustubh Patange
Kaustubh Patange
Memory efficient android library for managing individual fragment backstack.

fragstack : Android library for managing individual fragment backstack. An Easy to use library for managing individual fragment back stack as Instagra

Abhishesh 21 Feb 6, 2021
[ACTIVE] Simple Stack, a backstack library / navigation framework for simpler navigation and state management (for fragments, views, or whatevers).

Simple Stack Why do I want this? To make navigation to another screen as simple as backstack.goTo(SomeScreen()), and going back as simple as backstack

Gabor Varadi 1.3k Jan 2, 2023
Android Navigation Fragment Share Element Example: Use Share Element Transition with recyclerView Item and ViewPager2 Item.

Android-Navigation-Fragment-Share-Element-Example 说明 Android 使用Navigation导航切换Fragment中使用共享元素过渡动画的例子:将在listFragment的RecyclerView的Item共享元素过渡到pagerFragme

null 3 Sep 28, 2022
AndroidBriefActions - Android library for sending and observing non persistent actions such as showing a message; nice readable way to call navigation actions from ViewModel or Activity/Fragment.

implementation "com.vladmarkovic.briefactions:briefactions:$briefActionsVersion" Benefits Why use brief-actions library pattern: Prevent short-term ac

null 2 Dec 22, 2022
Bottom-App-Bar-with-Bottom-Navigation-in-Jetpack-compose-Android - Bottom App Bar with Bottom Navigation in Jetpack compose

Bottom-App-Bar-with-Bottom-Navigation-in-Jetpack-compose-Android This is simple

Shruti Patel 1 Jul 11, 2022
Tugas Fragment Codelab Navigation Pemrograman Mobile

AndroidTrivia - starter code Starter code for Android Kotlin Fundamentals codelab 3.1: Create and add a fragment. Introduction The AndroidTrivia app a

null 0 Nov 3, 2021
A small and simple, yet fully fledged and customizable navigation library for Jetpack Compose

A small and simple, yet fully fledged and customizable navigation library for Jetpack Compose

Vitali Olshevski 290 Dec 29, 2022
Use Fragment like Activity

Fragivity : Use Fragment like Activity English | 中文文档 Fragivity is a library used to build APP with "Single Activity + Multi-Fragments" Architecture R

fundroid 278 Nov 22, 2022
Ahmad Shahwaiz 1 Jan 26, 2022
Android multi-module navigation built on top of Jetpack Navigation Compose

MultiNavCompose Android library for multi-module navigation built on top of Jetpack Navigation Compose. The goal of this library is to simplify the se

Jeziel Lago 21 Dec 10, 2022
New style for app design simple bottom navigation with side navigation drawer UI made in Jetpack Compose.😉😎

BottomNavWithSideDrawer New style for app design simple bottom navigtaion with side navigation drawer UI made in Jetpack Compose. ?? ?? (Navigation Co

Arvind Meshram 5 Nov 24, 2022
DSC Moi University session on using Navigation components to simplify creating navigation flow in our apps to use best practices recommended by the Google Android Team

Navigation Components Navigate between destination using safe args How to use the navigation graph and editor How send data between destinations Demo

Breens Mbaka 6 Feb 3, 2022
Animated Tab Bar is an awesome navigation extension that you can use to add cool, animated and fully customizable tab navigation in your apps

Animated Tab Bar is an awesome navigation extension that you can use to add cool, animated and fully customizable tab navigation in your apps. The extension provides handy methods and properties to change the behaviour as well as the appearance of the navigation bar.

Zain Ul Hassan 4 Nov 30, 2022
A library that you can use for bottom navigation bar. Written with Jetpack Compose

FancyBottomNavigationBar A library that you can use for bottom navigation bar. W

Alperen Çevlik 3 Jul 27, 2022
Alligator is a modern Android navigation library that will help to organize your navigation code in clean and testable way.

Alligator Alligator is a modern Android navigation library that will help to organize your navigation code in clean and testable way. Features Any app

Artur Artikov 290 Dec 9, 2022
Navigation Component: THE BEST WAY to create navigation flows for your app

LIVE #017 - Navigation Component: A MELHOR FORMA de criar fluxos de navegação para o seu app! Código fonte do projeto criado na live #017, ensinando c

Kaique Ocanha 4 Jun 15, 2022
Navigation Drawer Bottom Navigation View

LIVE #019 - Toolbar, Navigation Drawer e BottomNavigationView com Navigation Com

Kaique Ocanha 6 Jun 15, 2022
🛸Voyager is a pragmatic navigation library built for, and seamlessly integrated with, Jetpack Compose.

Voyager is a pragmatic navigation library built for, and seamlessly integrated with, Jetpack Compose.

Adriel Café 831 Dec 26, 2022
Implementing bottom navigation in jetpack compose

Compose-Bottom-Navigation Implementing bottom navigation in jetpack compose Add the Navigation dependency Open the app's build file, found at app/buil

Steve Chacha 5 Dec 26, 2021