Giter Club home page Giter Club logo

trickynavigationsample's Introduction

TrickyNavigationSample

This repository contains some tricks about Android Navigation Component. 3rd party libraries not used.

Outputs

Default Bottom Behaviour Tricky Bottom Behaviour

Android Navigation Component default behavior hasn't got bottom navigation back stack. If you wanna add back stack to your bottomNavigationMenu it's easy and simple. Just add:

android:menuCategory="secondary"

to your all menu items.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/homeFragment"
        android:icon="@drawable/ic_home"
        android:menuCategory="secondary"
        android:title="Home" />

    <item
        android:id="@+id/searchFragment"
        android:icon="@drawable/ic_search"
        android:menuCategory="secondary"
        android:title="Search" />

    <item
        android:id="@+id/gamesFragment"
        android:icon="@drawable/ic_games"
        android:menuCategory="secondary"
        android:title="Games" />

    <item
        android:id="@+id/notificationsFragment"
        android:icon="@drawable/ic_notifications"
        android:menuCategory="secondary"
        android:title="Notifications" />
</menu>
menuCategory="secondary" Tricky "secondary"

With adding secondary to your items you gonna have backstack but if you want a stack like in Instagram or Youtube make the following changes:

First of all we need an extension for our navController.

fun NavController.popBackStackAllInstances(destination: Int, inclusive: Boolean): Boolean {
    var popped: Boolean
    while (true) {
        popped = popBackStack(destination, inclusive)
        if (!popped) {
            break
        }
    }
    return popped
}

Then extend your bottom tab fragments from BaseBottomTabFragment, don't forget to use utils functions when you try to navigate from tab starter fragments.

BaseBottomTabFragment has onBackPressedDispatcher for handling back press. Also it has isNavigated boolean, because if it's trying to navigate in same tab we don't need to addCallback.

open class BaseBottomTabFragment : Fragment() {
    var isNavigated = false

    fun navigateWithAction(action: NavDirections) {
        isNavigated = true
        findNavController().navigate(action)
    }

    fun navigate(resId: Int) {
        isNavigated = true
        findNavController().navigate(resId)
    }

    override fun onDestroyView() {
        super.onDestroyView()
        if (!isNavigated)
            requireActivity().onBackPressedDispatcher.addCallback(this) {
                val navController = findNavController()
                if (navController.currentBackStackEntry?.destination?.id != null) {
                    findNavController().popBackStackAllInstances(
                        navController.currentBackStackEntry?.destination?.id!!,
                        true
                    )
                } else
                    navController.popBackStack()
            }
    }
}

With this trick we have a back stack like Instagram and Youtube but we forgot something. As you know if you setup your toolbar with navController, your back press behaviour works with navController and onBackPressedDispatcher just affects your activiy's back press. If you wanna get the same bottom behavior with your toolbar navigate button. Add to following code to your activity:

binding.toolbar.setNavigationOnClickListener {
    when (navController.currentDestination?.id) {
        R.id.searchFragment, R.id.gamesFragment, R.id.notificationsFragment -> {
            if (onBackPressedDispatcher.hasEnabledCallbacks())
                onBackPressedDispatcher.onBackPressed()
            else
                navController.navigateUp()
        }
        else -> navController.navigateUp()
    }
 }
Dynamic Label

As you know, if you setup your toolbar with navController, your toolbar titles handling from navController. Navcontroller uses your fragment labels as title. For making this dynamically we need to use Android Navigation Component - SafeArgs

Define your argument as string in nav_graph

<fragment
    android:id="@+id/dynamicTitleFragment"
    android:name="com.faskn.trickynavigationsample.fragments.DynamicTitleFragment"
    android:label="{title}"
    tools:layout="@layout/fragment_dynamic_title" >
    <argument
        android:name="title"
        app:argType="string"
        android:defaultValue="Title" />
</fragment>

don't forget to use your argument as label

android:label="{title}"

and then pass data between destinations

binding.buttonDynamicTitleNavigate.setOnClickListener {
    navigateWithAction(
        SearchFragmentDirections.actionSearchFragmentToDynamicTitleFragment(
            binding.editTextTitle.text.toString()
        )
    )
 }
Default Replace Tricky Replace

As you know, if you call findNavController().navigate() it replaces your current fragment with other and when you call back press maybe your state is not saved. The easiest solution is passing id to your all views. It works with ScrollView, Recyclerview, etc..

But the best solution is Event.kt or EventObserver.kt

Tricky Add

With Android Navigation Component you can't add any fragment to your container. But you just wanna add 3-4 fragment to your navController you can use this solution.

Navigation Component 2.1.0 supports <dialog> tag in navigation graph.

This trick uses BottomSheetDialogFragment as fullscreen and with isDraggable = false attribute. It works like add. But adding too many screens can cause performance issues. Be careful.

trickynavigationsample's People

Contributors

furkanaskin avatar nuhkoca avatar

Stargazers

Ali Ammar avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.