How to fully implement the Navigation Drawer template in Kotlin - android

I'm expecting this to be a really simple answer. I am developing my first real app on android (a workout tracker) and I am wanting it to have a navigation drawer layout for the majority of the app. I have a bunch of pages that I want the drawer to navigate to. I have figured out how to change the names of the menu items in activity_main_drawer.xml menu file, but I don't know how to attach a navigation to when the user taps on them. My code is the default code from the template:
MainActivity.kt
package com.example.grahamfitnesstracker
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import android.support.design.widget.Snackbar
import android.support.v4.view.GravityCompat
import android.support.v7.app.ActionBarDrawerToggle
import android.view.MenuItem
import android.support.v4.widget.DrawerLayout
import android.support.design.widget.NavigationView
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.view.Menu
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val fab: FloatingActionButton = findViewById(R.id.fab)
fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val toggle = ActionBarDrawerToggle(
this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close
)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
navView.setNavigationItemSelectedListener(this)
}
override fun onBackPressed() {
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
return when (item.itemId) {
R.id.action_settings -> true
else -> super.onOptionsItemSelected(item)
}
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
// Handle navigation view item clicks here.
when (item.itemId) {
R.id.nav_current_workout -> {
// Handle the camera action
}
R.id.nav_log -> {
}
R.id.nav_exercises -> {
}
R.id.nav_workouts -> {
}
R.id.nav_stats -> {
}
R.id.nav_settings -> {
}
}
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
drawerLayout.closeDrawer(GravityCompat.START)
return true
}
}
And the nav drawer menu activity_main_drawer.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<group android:checkableBehavior="single">
<item
android:id="#+id/nav_current_workout"
android:icon="#drawable/ic_menu_play_filled"
android:title="#string/menu_current_workout"/>
<item
android:id="#+id/nav_log"
android:icon="#drawable/ic_menu_log"
android:title="#string/menu_log"/>
<item
android:id="#+id/nav_exercises"
android:icon="#drawable/ic_menu_weight"
android:title="#string/menu_exercises"/>
<item
android:id="#+id/nav_workouts"
android:icon="#drawable/ic_menu_person"
android:title="#string/menu_workouts"/>
<item
android:id="#+id/nav_stats"
android:icon="#drawable/ic_menu_chart"
android:title="#string/menu_stats"/>
</group>
<item android:title="">
<menu>
<item
android:id="#+id/nav_settings"
android:icon="#drawable/ic_menu_settings"
android:title="#string/menu_settings"/>
</menu>
</item>
</menu
And finally content_main.xml which I assume is where I need to put fragments (which I still don't fully understand...). From one guide I changed it to including a FrameLayout as:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/app_bar_main"
tools:context=".MainActivity">
<!-- Note : This is the container Frame Layout for all the fragments-->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/mainFrame">
</FrameLayout>
</android.support.constraint.ConstraintLayout>
I really just don't know what to add into the onNavigationItemSelected items in MainActivity.kt in order to handle navigation. I have learned that I need to replace the content in content_main.xml with some fragment where I put in my page's ui, but I don't know how to do that. Can anyone help me out? I've looked at a bunch of examples, but they usually implement their own custom nav bars, or are using java which confuses me as a newcomer.

Have you included the NavigationView in your activity_main and add this nav_header_man to that view like this:
activity_main
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" >
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
And since you asked for what to add into the onNavigationItemSelected items in MainActivity.kt,
MainActivity.kt
override fun onNavigationItemSelected(item: MenuItem): Boolean {
// Handle navigation view item clicks here.
val i = Intent()
when (item.itemId) {
R.id.nav_current_workout -> {
i.setClass(this, CurrentWorkoutActivity::class.java)
startActivity(i)
}
R.id.nav_log -> {
//similarly start activity with Intent
}
R.id.nav_exercises -> {}
R.id.nav_workouts -> {}
R.id.nav_stats -> {}
R.id.nav_settings -> {}
}
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
drawerLayout.closeDrawer(GravityCompat.START)
return true
}
}
Hope this helps.

Xml Layout for navigation drawer:
<include
layout="#layout/dashboard_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/drawer_menu" />
Implementation In Kotlin file:
class MainActivity :
AppCompatActivity(),NavigationView.OnNavigationItemSelectedListener {
private lateinit var drawer: DrawerLayout
private lateinit var navigationView: NavigationView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar_main)
setSupportActionBar(toolbar)
drawer = findViewById(R.id.drawer_layout)
toggle = ActionBarDrawerToggle(
dis,
drawer,
toolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close
)
drawer.addDrawerListener(toggle)
toggle.setDrawerIndicatorEnabled(true)
toggle.syncState()
navigationView = findViewById(R.id.nav_view)
navigationView.setNavigationItemSelectedListener(dis)
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.login_signup -> {
startActivity(Intent(dis, LoginActivity::class.java).putExtra("go_to","0"))
}
}
drawer.closeDrawers()
return true
}
}

Related

Action Bar Drawer Toggle displayed on AppBar but not working?

I created a class called BaseActivity that all of the activities inherit from so that I can add the drawer layout in all of my activities.
The Drawer Toggle button is shown in the AppBar, but when I click on it nothing happens!
Here is the code for the BaseActivity.kt:
open class BaseActivity : AppCompatActivity() {
private var dl: DrawerLayout? = null
private var t: ActionBarDrawerToggle? = null
private var nv: NavigationView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.base_activity)
dl = findViewById(R.id.drawer_layout)
t = ActionBarDrawerToggle(this, dl, R.string.drawer_open, R.string.drawer_close)
supportActionBar?.setDisplayShowTitleEnabled(true);
supportActionBar?.setHomeButtonEnabled(true);
supportActionBar?.setDisplayHomeAsUpEnabled(true);
dl?.addDrawerListener(t!!)
t?.syncState()
nv = findViewById(R.id.navigation_view)
nv?.setNavigationItemSelectedListener(NavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.nav_note -> Toast.makeText(this#BaseActivity, "My Account", Toast.LENGTH_SHORT).show()
R.id.nav_calendar -> Toast.makeText(this#BaseActivity, "Settings", Toast.LENGTH_SHORT).show()
R.id.nav_trash -> Toast.makeText(this#BaseActivity, "Trash", Toast.LENGTH_SHORT).show()
else -> return#OnNavigationItemSelectedListener true
}
true
})
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return if (t?.onOptionsItemSelected(item) == true) {
true
} else super.onOptionsItemSelected(item!!)
}
}
and here the base_activity.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".BaseActivity">
<!--include layout="#layout/toolbar"/-->
<com.google.android.material.navigation.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="#menu/drawer_menu"
app:headerLayout="#layout/nav_header"/>
</androidx.drawerlayout.widget.DrawerLayout>
For the style I left it at DarkActionBar. Here is how it looks like Don't mind what's written there
I still cannot figure out what's wrong and why it doesn't work. I appreciate any suggestions from the community. Thank you.
So I kind of changed my code to this and it is working Here is the new code for BaseActivty class
open class BaseActivity : AppCompatActivity() {
//var toolbar: Toolbar? = null
var drawerLayout: DrawerLayout? = null
var drawerToggle: ActionBarDrawerToggle? = null
var navigationView: NavigationView? = null
var mContext: Context? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mContext = this#BaseActivity
setContentView(R.layout.base_activity)
}
override fun setContentView(layoutResID: Int) {
val fullView = layoutInflater.inflate(R.layout.base_activity, null) as DrawerLayout
val activityContainer = fullView.findViewById<View>(R.id.activity_content) as FrameLayout
layoutInflater.inflate(layoutResID, activityContainer, true)
super.setContentView(fullView)
}
private fun setUpNav() {
drawerLayout = findViewById<View>(R.id.drawer_layout) as DrawerLayout
drawerToggle = ActionBarDrawerToggle(
this#BaseActivity,
drawerLayout,
R.string.app_name,
R.string.app_name
)
drawerLayout!!.setDrawerListener(drawerToggle)
supportActionBar!!.setHomeButtonEnabled(true)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
navigationView = findViewById<View>(R.id.navigation_view) as NavigationView
// Setting Navigation View Item Selected Listener to handle the item
// click of the navigation menu
navigationView!!.setNavigationItemSelectedListener(NavigationView.OnNavigationItemSelectedListener { menuItem -> // Checking if the item is in checked state or not, if not make
// it in checked state
if (menuItem.isChecked) menuItem.isChecked = false else menuItem.isChecked = true
// Closing drawer on item click
drawerLayout!!.closeDrawers()
// Check to see which item was being clicked and perform
// appropriate action
val intent_calendar = Intent(this, CalendarActivity::class.java)
val intent_add_note = Intent(this, AddActivity::class.java)
val intent_note = Intent(this, MainActivity::class.java)
when (menuItem.itemId) {
R.id.nav_note -> this.startActivity(intent_note)
R.id.nav_calendar -> this.startActivity(intent_calendar)
R.id.nav_trash -> Toast.makeText(this, "Trash", Toast.LENGTH_SHORT).show()
R.id.nav_add_note -> this.startActivity(intent_add_note)
else -> return#OnNavigationItemSelectedListener true
}
false
})
// calling sync state is necessay or else your hamburger icon wont show
// up
drawerToggle!!.syncState()
}
public override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
setUpNav()
drawerToggle!!.syncState()
}
override fun onConfigurationChanged(newConfig: Configuration) {
if (newConfig != null) {
super.onConfigurationChanged(newConfig)
}
drawerToggle!!.onConfigurationChanged(newConfig)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return if (drawerToggle?.onOptionsItemSelected(item) == true) {
true
} else super.onOptionsItemSelected(item!!)
}
}
and here is the code for its xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".BaseActivity"
>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/activity_content"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="#menu/drawer_menu"
app:headerLayout="#layout/nav_header"/>
</androidx.drawerlayout.widget.DrawerLayout>
Here is the answer that helped me, (I didn't use a toolbar and i left the style to "Theme.AppCompat.Light.DarkActionBar") https://stackoverflow.com/a/42533759/15018682

Kotlin Android Navigation Drawer item onclick listener does not working

I know this already asked many times, but in my case, I still don't get it.
So I have a navigation drawer that set up in the MainActivity.kt (My app has many fragment that runs on this Activity).
MainActivity.kt
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
lateinit var drawerLayout: DrawerLayout
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
drawerLayout = binding.drawerLayout
//Get navigation controller of this App
val navController = this.findNavController(R.id.myNavHostFragment)
//Lock the Nav drawer
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
NavigationUI.setupWithNavController(binding.navView, navController)
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.nav_logout -> {
Toast.makeText(this, "Publication", Toast.LENGTH_SHORT).show()
Log.i("MainActivity", "Sign out clicked!")
}
R.id.nav_messages -> {
Toast.makeText(this, "Publication", Toast.LENGTH_SHORT).show()
}
}
binding.drawerLayout.closeDrawer(GravityCompat.START)
return true
}
// Set up the back button on action bar
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.myNavHostFragment)
return NavigationUI.navigateUp(navController, drawerLayout)
}
}
This is my Activity_main.xml
Activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.drawerlayout.widget.DrawerLayout
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/myNavHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph = "#navigation/navigation"
app:defaultNavHost = "true"
/>
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header"
app:menu="#menu/nav_drawer_menu"/>
</androidx.drawerlayout.widget.DrawerLayout>
</layout>
This is the menu layout for the navigation drawer:
nav_drawer_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group>
<item
android:id="#+id/nav_profile"
android:icon="#drawable/ic_person"
android:title="Profile"/>
<item
android:id="#+id/nav_messages"
android:icon="#drawable/ic_people"
android:title="Messages"/>
</group>
<item android:title="Account Settings">
<menu>
<item
android:id="#+id/nav_logout"
android:title="Sign Out"/>
</menu>
</item>
</menu>
This is how the navigation drawer looks like.
Am I missing something ? If there's anything unclear let me know.
You should use setNavigationItemSelectedListener.
Set a listener that will be notified when a menu item is selected.
navigationViewOBJ.setNavigationItemSelectedListener(this)
For DataBinding You should use
binding.navView.setNavigationItemSelectedListener(this)
I was facing the same issue and I changed my code in this manner to get Toast when Menuitems were select.
I removed NavigationView.OnNavigationItemSelectedListener this from
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener
created a variable in MainActivity class in MianActivity.kt
private lateinit var navView : NavigationView
assigned navView variable in override fun onCreate function like this by finding navigation view id like this
navView = findViewById(R.id.nav_menu)
which in your case is in activity_main.xml under this Section
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header"
app:menu="#menu/nav_drawer_menu"/>
Then I implemented this function for onclick select
navView.setNavigationItemSelectedListener {}
I wrote switch case in this function same as your code and now it is working for me fine.

Android navigation onNavigationItemSelected not called

I have this DrawerLayout
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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/stock_drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/stock_app_bar"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_stock_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/stock_nav_header"
app:menu="#menu/stock_activity_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
and then in the activity I have the following onCreate function:
class StockMainActivity: AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_stock_main)
val toolbar: Toolbar = findViewById(R.id.stock_toolbar)
setSupportActionBar(toolbar)
val drawerLayout: DrawerLayout = findViewById(R.id.stock_drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_stock_view)
navView.bringToFront()
navView.setNavigationItemSelectedListener { item ->
if (item.itemId == R.id.nav_stock_home) {
finish()
}
true
}
val navController = findNavController(R.id.nav_stock_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(setOf(
R.id.nav_stock_home,
R.id.stock_navigation_fragment
), drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_stock_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
But the navigation selected item listener is never called. It eventually navigates to the destination, but the listener is never called. I have checked similar posts, some suggesting to bring to the front the Navigation View, but to no avail. Please help ...
Ok, I have found the solution. I have put:
navView.bringToFront()
navView.setNavigationItemSelectedListener { item ->
if (item.itemId == R.id.nav_stock_home) {
finish()
}
true
}
At the end of onCreate... and it works now.

Android No view found for id when using toolbar button

when i click to toolbar button, galleryFragment should open thats what i want to do. But i got these error:
java.lang.IllegalArgumentException: No view found for id 0x7f080051 (com.example.myapplication:id/container) for fragment GalleryFragment{e255e88 (923e67b6-0b21-4fac-acf1-f85b79a3311a) id=0x7f080051}
My button id is: shop
you can see my codes in onOptionsItemSelected function.
do you have any ideas about it?
this is my MainActivity:
package com.example.myapplication
class MainActivity : AppCompatActivity() {
var manager = supportFragmentManager
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayShowTitleEnabled(false)
toolbar.setTitle("deneme")
val fab: FloatingActionButton = findViewById(R.id.fab)
fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow,
R.id.nav_tools, R.id.nav_share, R.id.nav_send
), drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.shop -> {
var GalleryFragment = GalleryFragment()
var transaction = manager.beginTransaction()
transaction.add(R.id.container, GalleryFragment) //->
transaction.commit()
}
}
return super.onOptionsItemSelected(item)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
This is my main xml(include my button):
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/shop"
android:title="shop"
android:icon="#drawable/shop"
app:showAsAction="always">
</item>
</menu>
this is my mainactivity.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include layout="#layout/toolbar">
</include>
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
create a framelayout or any other view and set id as
android:id="#+id/container" in your activity_main.xml layout file
then issue will be fixed.
Reason : R.id.container id is not found in your activity_main.xml file
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

DrawerLayout getting stuck on swipe

I am playing around with DrawerLayout and I am encountering an issue. Basically sometimes when i swipe from the edge of the screen the DrawerLayout will get stuck until i lift my finger off the screen (See screenshot below)
I am not sure what is up, I followed the code sample from the google sdk exactly. Any ideas?
And here is the only thing i have in my FragmentActivity:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String[] names =
getResources().getStringArray(R.array.nav_names);
ArrayAdapter<String> adapter =
new ArrayAdapter<String>(
getActionBar().getThemedContext(),
android.R.layout.simple_list_item_1, names);
final DrawerLayout drawer =
(DrawerLayout)findViewById(R.id.drawer_layout);
final ListView navList =
(ListView) findViewById(R.id.drawer);
navList.setAdapter(adapter);
navList.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent,
View view, final int pos, long id)
{
drawer.setDrawerListener(
new DrawerLayout.SimpleDrawerListener()
{
#Override
public void onDrawerClosed(View drawerView)
{
super.onDrawerClosed(drawerView);
}
});
drawer.closeDrawer(navList);
}
});
}
EDIT:I'm adding a bounty on this, as this is a very old issue that exists even today with the latest Android-X (sample available here). Here's how it looks:
I've reported about it to Google (here and later again here), but it didn't help.
I've tried all existing solutions here on this thread, and none worked. If anyone has a good workaround for this (while still using DrawerLayout or extending it, or something similar), please put a working solution.
Note that you can get around this 20dp peek feature by setting the clickable attribute to true on the FrameLayout within the DrawerLayout.
android:clickable="true"
for instance :
http://developer.android.com/training/implementing-navigation/nav-drawer.html
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true" />
<!-- The navigation drawer -->
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#111"
android:choiceMode="singleChoice"
android:divider="#android:color/darker_gray"
android:dividerHeight="1dp" />
</android.support.v4.widget.DrawerLayout>
If you had shown us your layout xml, we could see if you have DrawerLayout as ROOT element. And whether the inside two children are Main Layout and Navigation Drawer.
According to Create a Drawer Layout:
To add a navigation drawer, declare your user interface with a DrawerLayout object as the root view of your layout. Inside the DrawerLayout, add one view that contains the main content for the screen (your primary layout when the drawer is hidden) and another view that contains the contents of the navigation drawer.
I've managed to work around this by implementing this DrawerListener:
drawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
#Override
public void onDrawerStateChanged(int newState) {
super.onDrawerStateChanged(newState);
if (drawerLayout.isDrawerVisible(Gravity.LEFT) && !drawerLayout.isDrawerOpen(Gravity.LEFT)) {
drawerLayout.closeDrawer(Gravity.LEFT);
}
}
});
Whenever the state changes, if the drawer is visible but not open, it means it's 'peeking', so I close it.
This 20dp Peek feature can be achieved When user drags the drawer to 20dp than open the drawer.
Here is code working fine for me.
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
lateinit var mToggle: ActionBarDrawerToggle
lateinit var mDrawerLayout: DrawerLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val fab: FloatingActionButton = findViewById(R.id.fab)
fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
mDrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
mToggle = ActionBarDrawerToggle(
this, mDrawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close
)
mDrawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener {
override fun onDrawerStateChanged(newState: Int) {
Log.d("onDrawerStateChanged", "$newState")
mToggle.onDrawerStateChanged(newState)
}
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
if ((slideOffset >= (dpToPx(19.9f)/drawerView.width)) && (slideOffset <= (dpToPx(20.1f)/drawerView.width))){
Log.d("onDrawerSlide", "true")
mDrawerLayout.openDrawer(GravityCompat.START)
}
Log.d("onDrawerSlide", "$slideOffset")
mToggle.onDrawerSlide(drawerView,slideOffset)
}
override fun onDrawerClosed(drawerView: View) {
mToggle.onDrawerClosed(drawerView)
}
override fun onDrawerOpened(drawerView: View) {
mToggle.onDrawerOpened(drawerView)
}
})
mToggle.syncState()
navView.setNavigationItemSelectedListener(this)
}
override fun onBackPressed() {
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
return when (item.itemId) {
R.id.action_settings -> true
else -> super.onOptionsItemSelected(item)
}
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
// Handle navigation view item clicks here.
when (item.itemId) {
R.id.nav_home -> {
// Handle the camera action
}
R.id.nav_gallery -> {
}
R.id.nav_slideshow -> {
}
R.id.nav_tools -> {
}
R.id.nav_share -> {
}
R.id.nav_send -> {
}
}
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
drawerLayout.closeDrawer(GravityCompat.START)
return true
}
fun dpToPx(dps : Float) : Float{
return (dps * Resources.getSystem().displayMetrics.density)
}
}
I can't comment, but the highest voted answer works for me on Android 11. I did it like this:
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:openDrawer="start">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true" >
<include
layout="#layout/main_activity"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/side_nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="#menu/side_nav_menu"/>
</androidx.drawerlayout.widget.DrawerLayout>

Categories

Resources