Add Navigation Architecture Component in Eventyay Attendee

The eventyay attendee is an android app which allows users to discover events happening around the world using the Open Event Platform. It consumes the APIs of the open event server to get a list of available events and can get detailed information about them.

The project earlier used Fragment transition to handle fragment with multiple activities. Multiple activities are used because it is very complex to handle all fragment with a single activity using fragment transition. If we try to make a single activity application with fragment transition, it contains a lot of bugs with the back stack.

But we can use Navigation Architecture Component to efficiently make Eventyay attendee a single activity. It is the perfect technology to handle all fragments and authentication in a single activity with no bigs or back stack.

  • Issues with fragment transition and multiple activities
  • Why navigation architecture component?
  • Process for using Navigation Architecture Component in the application
  • Animation of fragments with Navigation Architecture Component
  • Conclusion
  • Resources 

Let’s analyze every step in detail.

Issues with fragment transition and multiple activities

  1. Need to handle back stack on each Fragment Transition
  2. Hard to debug
  3. This can leave your app in an unknown state when receiving multiple click events or during configuration changes.
  4. Fragment instances can be created
  5. Multiple activities make the app slower due to using multiple intents

Why navigation architecture component?

  1. Handling Fragment transactions
  1. Handling Up and Back actions correctly by default
  2. Providing standardized resources for animations and transitions
  3. Treating deep linking as a first-class operation
  4. Including Navigation UI patterns, such as navigation drawers and bottom navigation, with minimal additional work
  5. Providing type safety when passing information while navigating
  6. Visualizing and editing navigation graphs with Android Studio’s Navigation Editor

Steps involved in using Navigation Architecture Component in the application

Adding dependencies to build.gradle:

//Navigation
    implementation 'android.arch.navigation:navigation-fragment:1.0.0-alpha09'
    implementation 'android.arch.navigation:navigation-ui:1.0.0-alpha09'

Create new resources file for navigation graph under res -> navigation:

Add fragments in navigation_graph.xml with navigation editor. Let’s take one example:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"   android:id="@+id/mobile_navigation"
    app:startDestination="@id/eventsFragment">

    <fragment
        android:id="@+id/eventsFragment"
        android:name="org.fossasia.openevent.general.event.EventsFragment"
        android:label="EventsFragment" />
</navigation>

Here app:startDestination attribute is for the very first fragment after which app exit on back pressed.

Replace Frame layout with a fragment in the main activity layout file. And add the above navigation graph to it: 

<fragment
            android:id="@+id/frameContainer"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:background="@android:color/white"
            android:layout_weight="1"
            app:defaultNavHost="true"
            app:navGraph="@navigation/navigation_graph"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

Now, this fragment layout is directly connected with all fragments added in the navigation graph. We only need to navigate the fragment.

Set bottom navigation drawer with the navigation architecture component – 

First, we need to make the ids of menu component same as the ids of fragments in the navigation graph. Bottom navigation menu:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/eventsFragment"
        android:icon="@drawable/ic_baseline_event_24px"
        android:title="@string/events" />
    <item
        android:id="@+id/searchFragment"
        android:icon="@drawable/ic_search_grey_24dp"
        android:title="@string/search" />
    <item
        android:id="@+id/favoriteFragment"
        android:icon="@drawable/ic_baseline_favorite_border_24px"
        android:title="@string/likes" />
    <item
        android:id="@+id/orderUnderUserFragment"
        android:icon="@drawable/ic_baseline_ticket_24dp"
        android:title="@string/tickets" />
    <item
        android:id="@+id/profileFragment"
        android:icon="@drawable/ic_baseline_account_circle_24px"
        android:title="@string/profile" />
</menu>

Setup the bottom navigation menu with navigation controller:

// import require libraries
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.NavigationUI.setupWithNavController

// Set nav controller with host fragment using Kotlin smart cast
val hostFragment = supportFragmentManager.findFragmentById(R.id.frameContainer)
 if (hostFragment is NavHostFragment)
     navController = hostFragment.navController
setupWithNavController(navigationMenu, navController)

Navigate fragment for bottom naviagtion whenever required:

navController.navigate(R.id.munuItemId)

Navigate any fragment which is added in navigation graph with arguments:

import androidx.navigation.Navigation
findNavController(rootView).navigate(R.id.fragmentId,  arguments)

Add Animations for fragments using navigation architecture component

Add require animations in utils as navigation options:

fun getAnimFade(): NavOptions {
        val builder = NavOptions.Builder()
        builder.setEnterAnim(R.anim.fade_in)
        builder.setExitAnim(R.anim.fade_out)
        builder.setPopEnterAnim(R.anim.slide_in_left)
        builder.setPopExitAnim(R.anim.slide_out_right)
        return builder.build()
    }

    fun getAnimSlide(): NavOptions {
        val builder = NavOptions.Builder()
        builder.setEnterAnim(R.anim.slide_in_right)
        builder.setExitAnim(R.anim.slide_out_left)
        builder.setPopEnterAnim(R.anim.slide_in_left)
        builder.setPopExitAnim(R.anim.slide_out_right)
        return builder.build()
    }

Resource files for animations (fade_in, fade_out, slide_in_right, slide_out_left, slide_in_left, slide_out_right) are added in res -> anim.

Now add nav options whenever navigate to fragments:

import androidx.navigation.Navigation
import org.fossasia.openevent.general.utils.Utils
findNavController(rootView).navigate(R.id.fragmentId,  arguments, getAnimFade())

GIF

In a Nutshell

Single activity application is the future of Android and many apps are shifting towards single activity Architecture from multiple activity ones. This brings in ease to use and smooth user experience. In shifting to a single activity, we have used Navigation Architecture Component which is much more efficient than Fragment transition which has many bugs associated with it while converting the app to a single activity.

Resources

  1. Documentation for navigation architecture component: https://developer.android.com/topic/libraries/architecture/navigation/
  2. Google navigation codelab: https://codelabs.developers.google.com/codelabs/android-navigation/

Tags

Eventyay, open-event, Navigation, Fragment, FOSSASIA, GSoC, Android, Kotlin

Continue Reading Add Navigation Architecture Component in Eventyay Attendee

Bottom Navigation Bar in Open Event Android

Bottom navigation bar provides an easy access and convenient way for users to navigate in between different sections of an App where the sections are of equal importance. We use bottom navigation move between different fragments such as events screen, favorites, tickets profile and so on. This blog post will guide you on how its implemented in Open Event Android.

To create a bottom navigation bar first create items for your menu. Menu items will be rendered as elements of the bottom navigation bar. Add icon and title to your navigation item here.

   <item
       android:id=“@+id/navigation_profile”
       android:icon=“@drawable/ic_baseline_account_circle_24px”
       android:title=“@string/profile” />

After we have written menu xml for our navigation view, we will have to create a view for it. The following snippet of code creates a BottomNavigationView type view element on the screen with different attributes as specified and menu file as specified by app:menu. Make sure you have android support design dependency set up before this.

<android.support.design.widget.BottomNavigationView
           android:id=“@+id/navigation”
           android:layout_width=“match_parent”
           android:layout_height=“wrap_content”
           android:layout_gravity=“bottom”
           android:background=“?android:attr/windowBackground”
           app:itemBackground=“@android:color/white”
           android:foreground=“?attr/selectableItemBackground”
           app:itemTextColor=“@color/colorPrimaryDark”
           app:menu=“@menu/navigation” />

No that our view will be created we need to wire menu items with different fragment and set up listener for item selected events.

Inside onCreate of MainActivity we attach a ItemSelectListener with the bottom navigation bar, navigation.setOnNavigationItemSelectedListener(listener) .

private val listener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
       val fragment: Fragment
       when (item.itemId) {
           R.id.navigation_profile -> {
               supportActionBar?.title = “Profile”
               fragment = ProfileFragment()
               loadFragment(fragment)
               return@OnNavigationItemSelectedListener true
           }
           R.id.navigation_favorite -> {
               supportActionBar?.title = “Likes”
               fragment = FavoriteFragment()
               loadFragment(fragment)
               return@OnNavigationItemSelectedListener true
           }
           R.id.navigation_tickets -> {
               supportActionBar?.title = “Tickets”
               fragment = OrdersUnderUserFragment()
               loadFragment(fragment)
               return@OnNavigationItemSelectedListener true
           }
       }
       false
   }

The above listener object listens for item selection in the bottom navigation bar. Whenever any item is selected lambda function is executed and item.itemId is matched with different menu item ids. On any successful match, an instance of the fragment corresponding to the selected item is loaded.

References

Continue Reading Bottom Navigation Bar in Open Event Android