Search code examples
androidandroid-fragmentsandroid-activityevent-handlingnavigation-drawer

Android Navigation Drawer with multiple Activity


I am trying to create a BaseActivity with navigation drawer and extend it in other activities so that I can reuse the the navigation drawer code.

What I have figured out so far:

  • I can use fragments to do this (which I can do).
  • I can use a BaseActivity and inflate the content area (Frame layout with id as “main_container” in my case) to show other activities. In this case I have figured out how to click on navigation drawer items to change activity.

However, when I have a button inside one of my activity (example activityA) and I want to load another activity (activityB), show a toast, etc. by clicking that button, the click listener does not work unless I write the code for the listener inside the onCreate method of the BaseActivity.

To me this does not make sense because it forces me to write all the codes inside the BaseActivity which is not the most efficient way of writing code (the activities acts like fragments so I can just use fragments instead).

What I want to know is, how to load the navigation drawer on all activities extending the BaseActivity, and still allow the activities to retain their behaviours.

Code samples

My activity_home.xml (BaseActivity)

<?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"
    android:id="@+id/drawer_layout"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeActivity"
tools:openDrawer="start"
android:fitsSystemWindows="true">

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

    <include
        android:id="@+id/custom_tool"
        layout="@layout/custom_bar"/>


    <FrameLayout
        android:id="@+id/main_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

<android.support.design.widget.NavigationView
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:id="@+id/nav_display"
    app:menu="@menu/nav_drawer_menu"
    android:layout_gravity="start"
    app:headerLayout="@layout/nav_header"/>

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

activity_main.xml (activityA)

<?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"
    tools:context=".MainActivity">

<ImageView
    android:id="@+id/imageView"
    android:layout_width="0dp"
    android:layout_height="147dp"
    android:layout_marginStart="105dp"
    android:layout_marginLeft="105dp"
    android:layout_marginTop="150dp"
    android:layout_marginEnd="105dp"
    android:layout_marginRight="105dp"
    android:layout_marginBottom="48dp"
    android:contentDescription="@string/app_logo"
    app:layout_constraintBottom_toTopOf="@+id/search_bar"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="1.0"
    app:srcCompat="@mipmap/ic_launcher" />


<SearchView
    android:id="@+id/search_bar"
    android:layout_width="0dp"
    android:layout_height="48dp"
    android:layout_marginStart="50dp"
    android:layout_marginLeft="50dp"
    android:layout_marginTop="48dp"
    android:layout_marginEnd="50dp"
    android:layout_marginRight="50dp"
    android:layout_marginBottom="50dp"
    android:background="@drawable/input_default"
    android:gravity="center"
    app:layout_constraintBottom_toTopOf="@+id/search_button"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/imageView" />

<Button
    android:id="@+id/search_button"
    android:layout_width="0dp"
    android:layout_height="48dp"
    android:layout_marginStart="150dp"
    android:layout_marginLeft="150dp"
    android:layout_marginTop="50dp"
    android:layout_marginEnd="150dp"
    android:layout_marginRight="150dp"
    android:layout_marginBottom="228dp"
    android:background="@drawable/button_default"
    android:text="@string/search"
    android:textColor="@color/colorAccent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/search_bar" />

</android.support.constraint.ConstraintLayout>

When the app is initially loading the “main_content” of the BaseActivity is inflated with the activity_main layout.

When I clicked the search_button inside the activity_main.xml, I want to load another activity which is only happening when I am writing the code inside the base activity.

HomeActivity

package com.example.naisse;


import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Toast;

public class HomeActivity extends AppCompatActivity {

protected static int position;
private DrawerLayout drawer;
protected FrameLayout frames;

Button searchButton;
/**
 *  This flag is used just to check that launcher activity is called first time
 *  so that we can open appropriate Activity on launch and make list item position selected accordingly.
 * */
private static boolean isLaunch = true;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);

    Toolbar toolbar = findViewById(R.id.custom_tool);
    setSupportActionBar(toolbar);

    drawer = findViewById(R.id.drawer_layout);

    frames = findViewById(R.id.main_container);

    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.addDrawerListener(toggle);
    toggle.syncState();


    /*inflating the layout with activity_main*/
    getLayoutInflater().inflate(R.layout.activity_main, frames);



    searchButton = findViewById(R.id.search_button);

    searchButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            /*removing the activity_main and inflating they layout with activity_result*/
            frames.removeAllViews();
            getLayoutInflater().inflate(R.layout.activity_result, frames);
        }
    });
}

@Override
public void onBackPressed() {
    if(drawer.isDrawerOpen(GravityCompat.START)){
        drawer.closeDrawer(GravityCompat.START);
    }else{
        super.onBackPressed();
    }
}
}

Extending MainActivity with HomeActivity

MainActivity

package com.example.naisse;

import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends HomeActivity {



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


}

}

How to solve this issue?


Solution

  • For answer and understanding, please read the discussion between me and Mike M.

    What I was initially doing was inflating the "main_container" with layout and therefore the Activity class was not getting triggered. To do that, I had to override setContentView() method inside the BaseActivity (HomeActivity in my case) and put every sharable code such as toolbar and navigation drawer inside that.

    My new HomeActivity.class

    public class HomeActivity extends AppCompatActivity {
    
    private DrawerLayout drawer;
    protected FrameLayout frames;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
    }
    
    @Override
    public void onBackPressed() {
        if(drawer.isDrawerOpen(GravityCompat.START)){
            drawer.closeDrawer(GravityCompat.START);
        }else{
            super.onBackPressed();
        }
    }
    
    
    @Override
    public void setContentView(int layoutResID) {
        // Set the base layout
        super.setContentView(R.layout.activity_home);
    
        // Find the content container
        frames = findViewById(R.id.main_container);
    
        // Inflate the extending Activity's layout into it
        getLayoutInflater().inflate(layoutResID, frames);
    
        // The rest of the base setup
        Toolbar toolbar = findViewById(R.id.custom_tool);
        setSupportActionBar(toolbar);
    
        drawer = findViewById(R.id.drawer_layout);
    
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();
    }
    
    }
    

    And now the toolbar and navigation drawer is shared across all activities.