Exploring Android Navigation Architecture Component - MVVM - Kotlin


Navigation Architecture Component is released as a part of JetPack and androidx package. Its aim is to simplify the implementation of Navigation in our Android App. It defines a set of principles to build an in-app navigation with consistent and predictable user experience. Its main concept is to use single-activity architecture. It also has support for both Activity and Fragment.

Principle of Navigation:

The following are the principles of Navigation.
  • App should have fixed starting destination
  • A stack is used to represent the navigation state of app
  • The 'Up' button never exits the app
  • Up and Back are equivalent within your app's task
  • Deep linking to a destination or navigating to the same destination should yield the same stack
You can find the detailed explanation, here.

Components of Navigation:

(i) Navigation Graph - It's nothing but a map/blueprint of our in-app navigation. It has a list of all fragments and activities. We can also specify argument, actions to the destinations.

(ii) Actions -  It specifies the destination fragment, transitions, arguments to that fragment and its pop behavior.

   <fragment
        android:id="@+id/main_frag"
        android:name="com.example.app.MainFragment"
        android:label="Home"
        tools:layout="@layout/main_fragment">

        <action
            android:id="@+id/open_details"
            app:destination="@id/details_fragment" />

    </fragment>

(iii) Arguments - Arguments can be passed either by old-fashioned bundle or with safeargs plugin. If you have boilerplate code, then you can go for safeargs, it is also type safe. We have add argument in destination activity/fragment. And it will generate two classes namely, HomeActivityDirections (Source class name+'Directions') class and DetailActivityArgs (destination class name + 'Args') class. Using this we can pass and get the arguments easily.

    <activity
        android:id="@+id/details_fragment"
        android:name="com.example.app.ui.detail.DetailActivity"
        android:label="@string/post_detail"
        tools:layout="@layout/detail_page">

        <argument
            android:name="id"
            app:type="integer" />

    </activity>

We can also add default value for the argument.

Pass Argument's value :

val direction = HomeFragmentDirections.Open_details(user.id)
findNavController(itemView).navigate(direction)

Get Argument's value :



val id = DetailActivityArgs.fromBundle(intent.extras).id  //In Activity
val id = DetailActivityArgs.fromBundle(arguments).id  // In Fragment

Setup

We have to use Android Studio 3.2 Canary 14 to use Navigation Architecture component and JetPack.
  • Create a New Project with it. You will find a new option while creating it like, Actvitiy+Fragment+ViewModel to take advantage of Android Architecture Components. Choose that and complete the project creation.


  • For now we can't use androidx, since it is under development. So we can use like below for now:
  implementation 'android.arch.lifecycle:extensions:1.1.1'
    implementation 'android.arch.navigation:navigation-fragment-ktx:1.0.0-alpha01'
    implementation 'android.arch.navigation:navigation-ui-ktx:1.0.0-alpha01'
  • Also, add navigation-safeargs, if you would like to pass parameter/arguments to other Fragment or Activity.
(i) In Project-level gradle:
buildscript {
    dependencies {
        classpath 'android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha01'
    }
}

(ii) In app-level gradle:
  apply plugin: 'androidx.navigation.safeargs'

Implementation:

(i) Using BottomNavigation:

First, let's create a Home page, that has BottomNavigationView of 2 tabs, home and profile and a Detail page, where the post's detail which the user clicked on Home, will be shown.

Basic Structure

Our basic structure of our app's package will be as follows :


nav_graph.xml

Let's create navigation graph first, by right click on res and then select New -> Android Resource Directory. Then choose navigation on Resource type on Dialog. Then create a Navigation Resource file, under that directory.

It can contain either Fragment or Activity. But first, it should have app:startDestination, from where the app will start. And then the destination have to be included as action. We can also declare parameters and its type here.

nav_gragh.xml

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    app:startDestination="@id/home_frag">

    <fragment
        android:id="@+id/home_frag"
        android:name="com.yamikrish.app.slicedemo.ui.home.HomeFragment"
        android:label="Home"
        tools:layout="@layout/home_fragment">

        <action
            android:id="@+id/open_details"
            app:destination="@id/details_fragment" />

    </fragment>

    <activity
        android:id="@+id/details_fragment"
        android:name="com.yamikrish.app.slicedemo.ui.detail.DetailActivity"
        android:label="@string/post_detail"
        tools:layout="@layout/detail_page">

        <argument
            android:name="id"
            app:type="integer" />

    </activity>

    <fragment
        android:id="@+id/profile_frag"
        android:name="com.yamikrish.app.slicedemo.ui.profile.ProfileFragment"
        android:label="@string/profile"
        tools:layout="@layout/profile_fragment" />
</navigation>

BaseActivity.kt

This is the launching activity of our Application, from where the app should navigate to other pages. We gonna have BottomNavigationView with two tabs, Home and Profile. Also, we have to integrate BottomNavigationView with NavController to manage the navigations, using the following line:

bottomTab.let { NavigationUI.setupWithNavController(bottomTab, controller.navController) 

Also don't forget to add, nav_graph with app:navGraph attribute to the fragment.

class BaseActivity : AppCompatActivity() {

    lateinit var controller: NavHostFragment

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.base_activity)

        controller = supportFragmentManager.findFragmentById(R.id.container) as NavHostFragment
        bottomTab.let { NavigationUI.setupWithNavController(bottomTab, controller.navController) }
    }

    override fun onSupportNavigateUp(): Boolean {
        return  findNavController(R.id.container).navigateUp()
    }

}

base_acivity.xml


In this layout, we can have BottomNavigationView and a Fragment, where the pages to be loaded and navigated.


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/bottomTab"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:menu="@menu/bottom_navigation"
        app:elevation="4dp"/>

    <View
        android:id="@+id/view"
        android:layout_width="0dp"
        android:layout_height="0.5dp"
        android:background="@android:color/darker_gray"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/bottomTab"/>

    <fragment 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/container"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/view"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph"
        tools:context=".BaseActivity" />

</android.support.constraint.ConstraintLayout>

bottom_navigation.xml


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@id/home_frag"
        android:icon="@drawable/home"
        android:title="@string/home"/>

    <item
        android:id="@id/profile_frag"
        android:icon="@drawable/profile"
        android:title="@string/profile"/>

</menu>

HomeFragment.kt

It is one of the tabs in BottomViewNavigation. It is to display the list of posts and while on a particular post, it will be redirected to DetailActivity, where the post's detail will be shown. HomeViewModel is used here to fetch posts from API using APIService

class HomeFragment : Fragment() {

    companion object {
        fun newInstance() = HomeFragment()
    }

    private lateinit var viewModel: HomeViewModel
    lateinit var adapter : PostAdapter
    var data: List<Post> = ArrayList()


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View {
        return inflater.inflate(R.layout.home_fragment, container, false)
    }


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

        userList.layoutManager = LinearLayoutManager(context)
        adapter = PostAdapter(context!!, data)
        userList.adapter = adapter

        viewModel = ViewModelProviders.of(this).get(HomeViewModel::class.java)

        viewModel.fetchAllData().observe(this, object: Observer<List<Post>> {
            override fun onChanged(t: List<Post>?) {
                Log.v("users","users=="+t)
                adapter.addItems(t)
            }

        })

    }

}

home_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/userList"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>


PostAdapter.kt

Its an Adapter class to show the post's items. On clicking an item, it should open DetailActivity. We can navigate as follows:

                          findNavController(view).navigate(page)

We already discussed how to pass arguments for the class , above. So let's jump to code directly.

class PostAdapter (val context: Context, var data : List<Post>?) : RecyclerView.Adapter<PostAdapter.Holder>() {
    override fun onBindViewHolder(holder: Holder, position: Int) {
        holder.bindItems(data?.get(position))
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
        val v = LayoutInflater.from(context).inflate(R.layout.post_item, parent, false)
        return Holder(v)
    }

    override fun getItemCount(): Int = data?.size?:0

    fun addItems(t: List<Post>?) {
        data = t
        notifyDataSetChanged()
    }

    inner class Holder(itemView: View?) : RecyclerView.ViewHolder(itemView){
        fun bindItems(user: Post?){
            itemView.title.text =  user?.title
            itemView.description.text = user?.body

            itemView.setOnClickListener {
                val direction = HomeFragmentDirections.Open_details(user!!.id)
                findNavController(itemView).navigate(direction)
            }
        }
    }

}

post_item.xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:textAppearance="@android:style/TextAppearance.Medium"
        android:textStyle="bold"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/description"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:textAppearance="@android:style/TextAppearance.Small"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/title" />

    <View
        android:layout_width="0dp"
        android:layout_height="0.5dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/description"
        android:background="@android:color/darker_gray"/>

</android.support.constraint.ConstraintLayout>

HomeViewModel.kt


class HomeViewModel : ViewModel() {
    var list: LiveData<List<Post>>

    init {
        list =  APIService.getUserList()
    }

    fun fetchAllData() : LiveData<List<Post>> = list
}

ProfileFragment.kt

This activity is to display the user details like, Name, phone number and Address. Let's get those details using ProfileViewModel, where the API will be called and data will be fetched with APIService.


class ProfileFragment : Fragment() {

    companion object {
        fun newInstance() = ProfileFragment()
    }

    private lateinit var viewModel: ProfileViewModel
    lateinit var data: User


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View {
        return inflater.inflate(R.layout.profile_fragment, container, false)
    }


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



        viewModel = ViewModelProviders.of(this).get(ProfileViewModel::class.java)

        viewModel.fetchUser().observe(this, object : Observer<User> {
            override fun onChanged(t: User?) {
                Log.v("users", "users==" + t)
                setDataOnUI(t)
            }

        })


    }

    private fun setDataOnUI(user: User?) {
        user?.let {
            name.text = it.name
            email.text = it.email
            phone.text = it.phone
            address.text = it.address.suite + ", " + it.address.street+ ", " +
                    it.address.city+ " - " + it.address.zipcode
        }

    }

}

profile_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <ImageView
        android:id="@+id/image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/user"
        android:layout_margin="20dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

    <TextView
        android:id="@+id/name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:textStyle="bold"
        android:textAppearance="@android:style/TextAppearance.Medium"
        app:layout_constraintTop_toBottomOf="@+id/image"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

    <TextView
        android:id="@+id/email"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:textAppearance="@android:style/TextAppearance.Small"
        android:drawableLeft="@drawable/email"
        android:drawablePadding="5dp"
        app:layout_constraintTop_toBottomOf="@+id/name"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

    <TextView
        android:id="@+id/phone"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:drawableLeft="@drawable/phone"
        android:drawablePadding="5dp"
        android:textAppearance="@android:style/TextAppearance.Small"
        app:layout_constraintTop_toBottomOf="@+id/email"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

    <TextView
        android:id="@+id/address"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:drawableLeft="@drawable/address"
        android:drawablePadding="5dp"
        android:textAppearance="@android:style/TextAppearance.Small"
        app:layout_constraintTop_toBottomOf="@+id/phone"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

</android.support.constraint.ConstraintLayout>


ProfileViewModel.kt


class ProfileViewModel  : ViewModel() {
    var post: LiveData<User>

    init {
        post =  APIService.getUser()
    }

    fun fetchUser() : LiveData<User> = post
}

DetailActivity.kt


class DetailActivity : AppCompatActivity() {

    private lateinit var viewModel: DetailViewModel
    lateinit var post: Post

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.detail_page)
        val id = DetailActivityArgs.fromBundle(intent.extras).id
        val factory = CustomViewModelFactory(id)


        supportActionBar?.let {
            it.title = getString(R.string.post_detail)
            it.setDisplayShowHomeEnabled(true)
            it.setDisplayHomeAsUpEnabled(true)
        }

        viewModel = ViewModelProviders.of(this, factory).get(DetailViewModel::class.java)

        viewModel.fetchPostById().observe(this, object : Observer<Post> {
            override fun onChanged(t: Post?) {
                postTitle.text = t?.title
                description.text = t?.body
            }

        })
    }

    class CustomViewModelFactory(private val test: Int) : ViewModelProvider.NewInstanceFactory() {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return DetailViewModel(test) as T
        }
    }

    override fun onSupportNavigateUp(): Boolean {
        finish()
        return  true;
    }
}

detail_page.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/postTitle"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:textAppearance="@android:style/TextAppearance.Medium"
        android:padding="10dp"
        android:textStyle="bold"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/description"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:textAppearance="@android:style/TextAppearance.Small"
        android:padding="10dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/postTitle" />

</android.support.constraint.ConstraintLayout>

DetailViewModel.kt

class DetailViewModel(id: Int) : ViewModel() {
    var post: LiveData<Post>

    init {
        post =  APIService.getPostById(id)
    }

    fun fetchPostById() : LiveData<Post> = post
}

APIInterface.kt


interface APIInterface{
    @GET("posts")
    fun getPosts(): Call<List<Post>>

    @GET("posts/{postId}")
    fun getPostById(@Path(value = "postId", encoded = true)  postId : Int): Call<Post>

    @GET("users/1")
    fun getUser(): Call<User>
}

APIService.kt



class APIService {
    companion object {
        var apiInterface: APIInterface

        init {
            val retrofit = Retrofit.Builder()
                    .baseUrl(Utils.BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()

            apiInterface = retrofit.create(APIInterface::class.java)
        }


        fun getUserList(): LiveData<List<Post>> {
            val data = MutableLiveData<List<Post>>()

            apiInterface.getPosts().enqueue(object : Callback<List<Post>> {
                override fun onResponse(call: Call<List<Post>>, response: Response<List<Post>>) {
                    data.setValue(response.body())
                }

                override fun onFailure(call: Call<List<Post>>, t: Throwable) {
                    data.setValue(null)
                    t.printStackTrace()
                }
            })

            return data
        }

        fun getPostById(id:Int): LiveData<Post> {
            val data = MutableLiveData<Post>()

            apiInterface.getPostById(id).enqueue(object : Callback<Post> {
                override fun onResponse(call: Call<Post>, response: Response<Post>) {
                    data.setValue(response.body())
                }

                override fun onFailure(call: Call<Post>, t: Throwable) {
                    data.setValue(null)
                    t.printStackTrace()
                }
            })

            return data
        }

        fun getUser(): LiveData<User> {
            val data = MutableLiveData<User>()

            apiInterface.getUser().enqueue(object : Callback<User> {
                override fun onResponse(call: Call<User>, response: Response<User>) {
                    data.setValue(response.body())
                }

                override fun onFailure(call: Call<User>, t: Throwable) {
                    data.setValue(null)
                    t.printStackTrace()
                }
            })

            return data
        }

    }
}

Post.kt


data class Post(val id: Int, val title: String, val body: String)

User.kt

data class User(val name: String, val email: String, val phone: String, val address: Address) {
    data class Address(val suite: String, val street: String, val city: String, val zipcode: String)
}

Utils.kt

class Utils {
    companion object {
        val BASE_URL = "https://jsonplaceholder.typicode.com/"
    }
}

Run Application:


      

You can find the project on Github, here.

(ii) Using DrawerLayout:

I am gonna reuse the same pages and layouts, except BaseActivity.kt and its layout, base_activity.xml, where we have to use DrawerLayout and its NavigationView. Also make sure that, the menu option's id should be same as that of corresponding Fragment's id in nav_graph.xml.

menu/bottom_navigation.xml


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/home_frag"
        android:icon="@drawable/home"
        android:title="@string/home"/>

    <item
        android:id="@+id/profile_frag"
        android:icon="@drawable/profile"
        android:title="@string/profile"/>

</menu>



base_activity.xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 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/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

       <include
           layout="@layout/tool_bar"/>

        <fragment 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/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=".BaseActivity" />

    </LinearLayout>


    <android.support.design.widget.NavigationView
        android:id="@+id/navigationView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:elevation="4dp"
        app:menu="@menu/bottom_navigation" />

</android.support.v4.widget.DrawerLayout>

BaseActivity.kt

In this activity, ActionBarDrawerToggle will be used along with DrawerLayout, to sync its action. Then the navigationController should be set up for DrawerLayout. That's it!! nav_graph will handle the fragment adding/replacing operations for you.


class BaseActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.base_activity)

        val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)
        val actionbar: ActionBar? = supportActionBar
        actionbar?.apply {
            setDisplayHomeAsUpEnabled(true)
        }

        val mDrawerToggle = object : ActionBarDrawerToggle(this, drawerLayout, toolbar,
                R.string.open, R.string.close) {

            override fun onDrawerClosed(view: View) {
                super.onDrawerClosed(view)
            }

            override fun onDrawerOpened(drawerView: View) {
                super.onDrawerOpened(drawerView)
            }
        }
        drawerLayout.addDrawerListener(mDrawerToggle)
        mDrawerToggle.syncState()

        val controller = Navigation.findNavController(this, R.id.container)
        NavigationUI.setupWithNavController(navigationView, controller)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            android.R.id.home -> {
                drawerLayout.openDrawer(GravityCompat.START)
                true
            }
            else -> super.onOptionsItemSelected(item)
        }
    }

}

You can find the project on Github, here.

Run Application

    

Comments

  1. Could you share the code on github please? Btw thanks for sharing your post,

    ReplyDelete

Post a Comment

Popular posts from this blog

SOAP Client using ksoap2 in Android - Kotlin

RecyclerView with different number of columns using SpanSizeLookup

Map, Location update and AutoComplete Places - Kotlin

Stripe Integration in Android - Kotlin

TabLayout in Android with Kotlin

Room with LiveData, ViewModel - Android Architecture Components - Kotlin

Exploring Databinding Library in Android - Kotlin

Android JetPack - Scheduling Tasks with WorkManager

FCM Integration in Android - Kotlin

Using Camera in Android - Kotlin