6

I want to have a AbstractMainActivity which creates the Navigation Drawer. In there I should also handle the clicks on the menu items and then call new activities. In those activities, I want to again use the same Navigation Drawer.

I would extend in the Subclasses with the AbstractMainActivity and call the getLayoutResourceID differently from each subclass (as suggested here: android how to create my own Activity and extend it?).

The problem is, that now in the AbstractMainActivity where I want to build the Navigation Drawer, I do not have any access to the navigation drawer layout (xml) element, as I of course want to have a different base layout for the subclasses.

Would I need to "include layout" in all the subclasses layout files? But this does not work, what do I do wrong if I want to use Activities instead of Fragments with the Navigation Drawer?

public abstract class MainActivity extends Activity {

private String[] menuItems;
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;

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

    setContentView(getLayoutResourceId());

    menuItems = getResources().getStringArray(R.array.menu_items);
    mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    mDrawerList = (ListView) findViewById(R.id.left_drawer);

    // Set the adapter for the list view
    mDrawerList.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, menuItems));
    // Set the list's click listener
    mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

}


protected abstract int getLayoutResourceId();

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}


private class DrawerItemClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView parent, View view, int position, long id) {
        selectItem(position);
    }

    /** Swaps fragments in the main content view */
    private void selectItem(int position) {
        //Fragment fragment = new PlanetFragment();
        Bundle args = new Bundle();
       // args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);

        Intent intent = new Intent(MainActivity.this, ProductListActivity.class);
        startActivity(intent);

    }
}




public class ProductListActivity extends MainActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.options_menu, menu);
    return true;
}

@Override
protected int getLayoutResourceId() {
    // TODO Auto-generated method stub
    return R.layout.activity_product_list;
}

This is the layout of the product list sub-class (activity_product_list.xml):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".ProductList" >

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

<ListView
    android:id="@+id/listView1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true" >
</ListView>

This is the layout of the navigation drawer (activity_main.xml):

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android1="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="300dp"
android:layout_height="500dp" >

<!-- The main content view -->
<FrameLayout
    android:id="@+id/content_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
<!-- The navigation drawer -->
<ListView android:id="@+id/left_drawer"
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:choiceMode="singleChoice"
    android:divider="@android:color/transparent"
    android:dividerHeight="0dp"
    android:background="#c3c3c3"/>

But the does not work, but if I do not have it, I get null-pointer exceptions when my subclass calls the onCreate of the abstract class, where I want to build the Navigation Drawer, it does not find the layout-elements to set the lists and layout (R.id.left_drawer or R.id.drawer_layout)!

Community
  • 1
  • 1
fischer_zh
  • 730
  • 1
  • 8
  • 7

2 Answers2

12

I'm also trying to figure out how to do this.

I've seen a very good tutorial that does exactly what you want here. The idea is to create an abstract activity class AbstractNavDrawerActivity that all activities with drawers will inherit from. This class uses a NavDrawerActivityConfiguration bean class that holds all the information about the nav drawer including the layout that needs to be inflated

Another approach would be creating a NavDrawerUtil class where you would put static methods that interact with the nav drawer. You would then call these methods from each activity as you need.

The second approach gives you more flexibility and you don't have to worry about order of layout inflations and such but I think it's a less clean solution than the first one with the AbstractNavDrawerActivity that all activities with nav drawer inherit from like you suggested.

Michael
  • 22,196
  • 33
  • 132
  • 187
  • http://stackoverflow.com/a/4922740/3060087 is a simpler solution using the same approach. This example is for implementing the same sliding drawer in each Activity, but it can be adjusted for navigation drawer by simply replacing the LinearLayout in the DrawerActivity by DrawerLayout. – Price Aug 06 '14 at 04:09
1

What I've done in previous apps is have a sliding menu built as a function call in the abstract activity. When you set up a new Activity extending the abstract activity, you perform the function call in the onCreate(). I'm currently working on a similar implementation using the Navigation Drawer instead, so I'm not quite sure if it works yet, but it might be a good place for you to start. All your Activities that will call the Navigation Drawer will need to have a DrawerLayout as the top-level layout element.

supern00b
  • 11
  • 1
  • Thanks, so my approach is going into the right direction with including the drawer layout in the sub-activity layouts? Then I would be able to set-up the navigation drawer menu in the abstract class I guess, but somehow the "include" does not yet work. Worst case I have code-duplication in the layouts, but at least not in the activity code. – fischer_zh Aug 02 '13 at 07:51
  • Right. I've actually just implemented this and it works. Every new activity layout will need to have the DrawerLayout top-level and the included drawer elements. You should give the drawer elements the same id as they have in the abstract layout so that you can reuse the function call inherited from the abstract activity for the drawer. Unfortunately, since the design scheme for Android seems to be moving away from multiple Activities to one Activity with multiple fragments, I don't see them adding "include" functionality at any point soon. – supern00b Aug 07 '13 at 15:26