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
Related
When I try to add click listeners to the menu items using binding.navigationView.setNavigationItemSelectedListener, it throws me an error saying Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type NavigationView?
So when I add the safe call like this: binding.navigationView?.setNavigationItemSelectedListener, naturally the click listener doesn't work, neither do i get my toast message on clicking on the menu items nor does the fragment I've added in the dashboard menu item work.
When I add the non null asserted call, the app altogether crashes and gives me nullPointerException in the logcat.
Here is the kotlin code:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setUpToolbar()
val actionBarDrawerToggle = ActionBarDrawerToggle(
this#MainActivity,
binding.root,
R.string.open_drawer,
R.string.close_drawer)
binding.root.addDrawerListener(actionBarDrawerToggle)
actionBarDrawerToggle.syncState()
binding.navigationView.setNavigationItemSelectedListener {
when(it.itemId){
R.id.dashboard -> {
supportFragmentManager.beginTransaction()
.replace(R.id.frameLayout, DashboardFragment())
.commit()
binding.drawerLayout.closeDrawers()
}
R.id.favourites -> {
Toast.makeText (
this#MainActivity,
"Clicked on favourites",
Toast.LENGTH_LONG
).show()
}
R.id.profile -> {
Toast.makeText (
this#MainActivity,
"Clicked on profile",
Toast.LENGTH_LONG
).show()
}
R.id.aboutApp -> {
Toast.makeText (
this#MainActivity,
"Clicked on about",
Toast.LENGTH_LONG
).show()
}
}
return#setNavigationItemSelectedListener true
}
}
fun setUpToolbar(){
supportActionBar?.title = "Toolbar Title"
supportActionBar?.setHomeButtonEnabled(true)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
if(id == android.R.id.home){
binding.root.openDrawer(GravityCompat.START)
}
return super.onOptionsItemSelected(item)
}
}
here is the xml code:
<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:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/drawerLayout"
tools:context=".MainActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="#+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:background="#color/design_default_color_primary_dark"
android:theme="#style/ThemeOverlay.AppCompat.Dark"/>
<FrameLayout
android:id="#+id/frameLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/navigationView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:headerLayout="#layout/drawer_header"
app:menu="#menu/menu_drawer"
android:layout_gravity = "start"/>
</androidx.drawerlayout.widget.DrawerLayout>
It'd be great if someone could point out where I'm going wrong
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.
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
}
}
I'm developing an Android app (I'm a newbie) that uses a Navigation Drawer. I've created multiple fragments that represent the various item in the side menu. One of them has a RecyclerView, and I want to show another fragment with various details when the user clicks one of the item of the RecyclerView.
I've created the structure successfully, implement the click listener on the RecyclerView item, but I don't know how to show the details fragment (and how to go back from it).
If showing another fragment is not the right way, please suggest me the best way to obtain the navigation that I need.
CODE
MenuActivity.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"
tools:openDrawer="start">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimaryDark"
android:theme="#style/AppTheme.AppBarOverlay"
app:popupTheme="#style/AppTheme.PopupOverlay"
app:titleTextColor="#android:color/white"/>
<FrameLayout
android:id="#+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/toolbar"/>
</RelativeLayout>
<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:menu="#menu/drawer_view"
app:headerLayout="#layout/nav_header"/>
MenuActivity.kt
class MenuActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
val vendutoFragment = VendutoFragment()
val prezziFragment = PrezziFragment()
val giacenzeFragment = GiacenzeFragment()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_menu)
setSupportActionBar(toolbar)
val toggle = ActionBarDrawerToggle(this, drawerLayout, toolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
navigationView.setNavigationItemSelectedListener(this)
if(savedInstanceState == null){
addFragment(vendutoFragment)
navigationView.setCheckedItem(nav_venduto)
}
}
override fun onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
var selectedFragment = Fragment()
when (item.itemId) {
R.id.nav_venduto -> {
selectedFragment = vendutoFragment
}
R.id.nav_prezzi -> {
selectedFragment = prezziFragment
}
R.id.nav_giacenze -> {
selectedFragment = giacenzeFragment
}
}
replaceFragment(selectedFragment)
drawerLayout.closeDrawer(GravityCompat.START)
return true
}
private fun addFragment(fragment: Fragment){
supportFragmentManager.beginTransaction().add(R.id.frameLayout, fragment).commit()
}
private fun replaceFragment(fragment: Fragment){
supportFragmentManager.beginTransaction().replace(R.id.frameLayout, fragment).commit()
}
}
1st Fragment with RecyclerView and clickable item
class GiacenzeFragment: Fragment(){
var global: Global? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
{
//returning our layout file
//change R.layout.yourlayoutfilename for each of your fragments
return inflater.inflate(R.layout.fragment_giacenze, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{
super.onViewCreated(view, savedInstanceState)
//you can set the title for your toolbar here for different fragments different titles
activity!!.title = "Giacenze"
}
override fun onActivityCreated(savedInstanceState: Bundle?)
{
super.onActivityCreated(savedInstanceState)
giacenzeTable.layoutManager = LinearLayoutManager(context) as RecyclerView.LayoutManager?
global = getActivity()?.getApplication() as Global
// Access the RecyclerView Adapter and load the data into it
giacenzeTable.adapter = GiacenzeTableAdapter(global!!.prodotti, { prodotto: Prodotto -> prodottoItemClicked(prodotto) })
}
private fun prodottoItemClicked(prodotto: Prodotto)
{
Toast.makeText(context, "Clicked: ${prodotto.name}", Toast.LENGTH_SHORT).show()
var serbatoiFrag = SerbatoiFragment()
serbatoiFrag.idProdotto = prodotto.idProdotto
serbatoiFrag.nameProdotto = prodotto.name
fragmentManager?.beginTransaction()!!.replace(R.id.frameLayout, serbatoiFrag).commit()
}
}
if you want to load fragment in a new activity, just open new activity and use replaceFragment
if you want to load in same activity, just use replaceFragment
do you know how to use replaceFragment?
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>