简体   繁体   English

如何在所有活动中显示导航抽屉?

[英]How to Display Navigation Drawer in all activities?

I have a Navigation Drawer which should appear in all my activities.我有一个Navigation Drawer ,它应该出现在我所有的活动中。

I saw many questions similar to this & found a solution like Extending the MainActivity with the Other Activities .我看到了很多与此类似的问题,并找到了一个解决方案,例如用其他活动扩展 MainActivity 。

So i extended My Main Activity to my Second Activity.But the Drawer is not being showed in the Second Activity所以我将我的主要活动扩展到我的第二个活动。但是抽屉没有在第二个活动中显示

MainActivity主要活动

public class MainActivity extends ActionBarActivity
{
    private ListView mDrawerList;
    private DrawerLayout mDrawer;
    private CustomActionBarDrawerToggle mDrawerToggle;
    private String[] menuItems;

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
    // getSupportActionBar().hide();
    setContentView(R.layout.activity_main_drawer);

    // enable ActionBar app icon to behave as action to toggle nav drawer
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setHomeButtonEnabled(true);

    mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);

    // set a custom shadow that overlays the main content when the drawer
    // opens
    mDrawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);

    _initMenu();
    mDrawerToggle = new CustomActionBarDrawerToggle(this, mDrawer);
    mDrawer.setDrawerListener(mDrawerToggle);

}

private void _initMenu()
{
    NsMenuAdapter mAdapter = new NsMenuAdapter(this);

    // Add Header
    mAdapter.addHeader(R.string.ns_menu_main_header);

    // Add first block

    menuItems = getResources().getStringArray(R.array.ns_menu_items);
    String[] menuItemsIcon = getResources().getStringArray(R.array.ns_menu_items_icon);

    int res = 0;
    for (String item : menuItems)
    {

        int id_title = getResources().getIdentifier(item, "string", this.getPackageName());
        int id_icon = getResources().getIdentifier(menuItemsIcon[res], "drawable", this.getPackageName());

        NsMenuItemModel mItem = new NsMenuItemModel(id_title, id_icon);
        // if (res==1) mItem.counter=12; //it is just an example...
        // if (res==3) mItem.counter=3; //it is just an example...
        mAdapter.addItem(mItem);
        res++;
    }

    mAdapter.addHeader(R.string.ns_menu_main_header2);

    mDrawerList = (ListView) findViewById(R.id.drawer);
    if (mDrawerList != null)
        mDrawerList.setAdapter(mAdapter);

    mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

}

@Override
protected void onPostCreate(Bundle savedInstanceState)
{
    super.onPostCreate(savedInstanceState);
    // Sync the toggle state after onRestoreInstanceState has occurred.
    mDrawerToggle.syncState();
}

@Override
public void onConfigurationChanged(Configuration newConfig)
{
    super.onConfigurationChanged(newConfig);
    mDrawerToggle.onConfigurationChanged(newConfig);
}

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.control_menu, menu);
    return super.onCreateOptionsMenu(menu);
}

/* Called whenever we call invalidateOptionsMenu() */
@Override
public boolean onPrepareOptionsMenu(Menu menu)
{
    // If the nav drawer is open, hide action items related to the content
    // view
    boolean drawerOpen = mDrawer.isDrawerOpen(mDrawerList);
    menu.findItem(R.id.action_keyboard).setVisible(!drawerOpen);
    return super.onPrepareOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
    /*
     * The action bar home/up should open or close the drawer.
     * ActionBarDrawerToggle will take care of this.
     */
    if (mDrawerToggle.onOptionsItemSelected(item))
    {
        return true;
    }

    // Handle your other action bar items...
    return super.onOptionsItemSelected(item);
}

private class CustomActionBarDrawerToggle extends ActionBarDrawerToggle
{

    public CustomActionBarDrawerToggle(Activity mActivity, DrawerLayout mDrawerLayout)
    {
        super(mActivity, mDrawerLayout, R.drawable.ic_drawer, R.string.ns_menu_open, R.string.ns_menu_close);
    }

    @Override
    public void onDrawerClosed(View view)
    {
        getSupportActionBar().setTitle(getString(R.string.ns_menu_close));
        supportInvalidateOptionsMenu(); // creates call to
                                        // onPrepareOptionsMenu()
    }

    @Override
    public void onDrawerOpened(View drawerView)
    {
        getSupportActionBar().setTitle(getString(R.string.ns_menu_open));
        supportInvalidateOptionsMenu(); // creates call to
                                        // onPrepareOptionsMenu()
    }
}

private class DrawerItemClickListener implements ListView.OnItemClickListener
{

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id)
    {
        Intent intent = new Intent(MainActivity.this, Tutorial.class);
        startActivity(intent);

    }

}

 }

SecondActivity第二个活动

 public class Tutorial extends MainActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.help);
    }

}

Here is my implementation.. hope it help 这是我的实施..希望它有所帮助

FIRST , this POST is concept. 首先 ,这个POST是概念。

SECOND , this is also the KEY one. 第二 ,这也是关键之一。

FINALLY , Here is combination of all answer in one place 最后 ,这是所有答案在一个地方的组合


BASE ACTIVITY 基础活动

This is a base activity for all other activity 这是所有其他活动的基本活动

You can extends Activity or FragmentActivity or etc. base on your requirement. 您可以根据您的要求扩展Activity或FragmentActivity等。

Navigation Drawer setup here for one time. Navigation Drawer在这里设置了一次。

public class BaseActivity extends FragmentActivity {

    protected DrawerLayout mDrawer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.base_layout);

        mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);

        //This is about creating custom listview for navigate drawer
        //Implementation for NavigateDrawer HERE !
        ArrayList<DrawerListItem> drawerListItems = new ArrayList<DrawerListItem>();
        drawerListItems.add(new DrawerListItem(0,"AIR° DEVICES"));
        drawerListItems.add(new DrawerListItem(1,"A/C Device [1]"));
        drawerListItems.add(new DrawerListItem(1,"A/C Device [2]"));
        drawerListItems.add(new DrawerListItem(1,"A/C Device [3]"));
        drawerListItems.add(new DrawerListItem(0,"AIR° FEATURES"));
        drawerListItems.add(new DrawerListItem(2,"SLEEP MODE"));
        drawerListItems.add(new DrawerListItem(2,"TRACKING MODE"));
        drawerListItems.add(new DrawerListItem(2,"SETTINGS"));
        DrawerAdapter mDrawerAdapter = new DrawerAdapter(this, R.layout.drawer_list_header, drawerListItems);
        ListView mDrawerList = (ListView) findViewById(R.id.left_drawer);
        mDrawerList.setAdapter(mDrawerAdapter);
    }

}

BASE ACTIVITY XML 基础活动XML

This xml layout is for Navigation Drawer 此xml布局适用于Navigation Drawer

<?xml version="1.0" encoding="utf-8"?>

<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">

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

    </FrameLayout>

    <!-- The navigation drawer -->
    <ListView
            android:id="@+id/left_drawer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="left"
            android:scrollingCache="false"
            android:background="@drawable/drawer_bg"
            android:divider="@null"
            android:choiceMode="singleChoice"/>

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

ALL OTHERS ACTIVITY 所有其他人的活动

Other Activity just extends BaseActivity and define code as below. 其他Activity只是扩展了BaseActivity并定义了如下代码。

The Navigation Drawer will appear for particular activity. Navigation Drawer将出现在特定活动中。

mDrawer is form BaseActivity . mDrawer是表单BaseActivity it's a protected variable. 它是一个protected变量。

public class Screen1 extends BaseActivity

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        //inflate your activity layout here!
        View contentView = inflater.inflate(R.layout.screen1, null, false);
        mDrawer.addView(contentView, 0);

        //Do the rest as you want for each activity
    }

SCREEN 1 XML SAMPLE 屏幕1 XML示例

Design as you wish it each activity. 按照您的意愿设计每项活动。 no more Navigation Drawer Layout ! 没有更多的Navigation Drawer布局!

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

</LinearLayout>

NOTE 注意

In this implementation, The Navigation Drawer doesn't bind with Action Bar. 在此实现中, Navigation Drawer不与Action Bar绑定。 If you wish to do that do it in BaseActivity .Also, This guide is not cover all requirement. 如果您希望这样做,请在BaseActivity 。此外,本指南并未涵盖所有要求。 It's just a sample. 这只是一个样本。

in onCreate of TutorialActivity don't call setContentView instead do this: onCreate of TutorialActivity不调用setContentView而是这样做:

@Override
protected void onCreate(Bundle savedInstanceState)
{
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    LayoutInflater inflater = (LayoutInflater) this
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View contentView = inflater.inflate(R.layout.help, null, false);
    mDrawer.addView(contentView, 0); 
}

make mDrawer in MainActivity protected. 使MainActivity mDrawer受到保护。 and in R.layout.activity_main_drawer just keep drawer tag and the element with gravity left(or right). R.layout.activity_main_drawer只需保留抽屉标签和重力元素左(或右)。

I made a BaseActivity activity which extends SherlockActivity (or ActionBarActivity if is your case) 我做了一个BaseActivity活动,它扩展了SherlockActivity(如果是你的话,还是ActionBarActivity)

public class BaseActivity extends SherlockActivity

Then, make all your activities extends BaseActivity, like: 然后,使所有活动扩展BaseActivity,如:

public class GlossaryActivity extends BaseActivity

Later, you must replace the activity layout with the one that correspond to your activity, I made a method in BaseActivity like that: 稍后,您必须将活动布局替换为与您的活动对应的活动布局,我在BaseActivity中创建了一个方法:

protected void replaceContentLayout(int sourceId, int destinationId) {
    View contentLayout = findViewById(destinationId);

    ViewGroup parent = (ViewGroup) contentLayout.getParent();
    int index = parent.indexOfChild(contentLayout);

    parent.removeView(contentLayout);
    contentLayout = getLayoutInflater().inflate(sourceId, parent, false);
    parent.addView(contentLayout, index);
}

I called this method on the onCreate method in each activity: 我在每个活动的onCreate方法上调用了这个方法:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    super.replaceContentLayout(R.layout.activity_glossary, super.CONTENT_LAYOUT_ID);

}

super.CONTENT_LAYOUT_ID is the FrameLayout of the BaseActivity, and other param is the layout you want replace with super.CONTENT_LAYOUT_IDsuper.CONTENT_LAYOUT_ID的FrameLayout,其他param是要替换的布局

You omitted the @Override from your derived class onCreate . 您从派生类onCreate省略了@Override

UPDATE: I'm not sure what the effects are of calling setContentView twice but that could be the problem. 更新:我不确定调用setContentView两次的效果是什么,但这可能是问题所在。 Separate out the code that sets up the drawer, and call that from both of the onCreate methods. 分离设置抽屉的代码,并从两个onCreate方法中调用它。

I had this problem too. 我也有这个问题。 This is my implementation: 这是我的实施:

activity_main.xml - the child at index 1 in the CoordinatorLayout is the content_main.xml , this I can change in code. activity_main.xml - CoordinatorLayout中索引1处的子节点content_main.xml ,我可以在代码中进行更改。

<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/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinator"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/AppTheme.PopupOverlay" />

        </android.support.design.widget.AppBarLayout>

        **<include layout="@layout/content_main" />**

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_margin="@dimen/fab_margin"
            android:src="@android:drawable/ic_dialog_email" />

    </android.support.design.widget.CoordinatorLayout>

    <android.support.design.widget.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" />

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

I've created a class that uses inflates the others activities UI: 我创建了一个使用膨胀其他活动UI的类:

public class MyLayoutInflater {

    public void inflate(Activity activity, int LayoutResource, android.app.ActionBar getSupportActionBar, Intent getIntent){
        CoordinatorLayout coordinatorLayout = (CoordinatorLayout) activity.findViewById(R.id.coordinator);
        android.view.LayoutInflater inflater = (android.view.LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View contentView = inflater.inflate(LayoutResource, null, false);

        //change i so that it suits the child number in you coordinator layout
        int i = 1;
        coordinatorLayout.removeViewAt(i);
        coordinatorLayout.addView(contentView, i);
        getSupportActionBar.setTitle(actionBarTitle);
    }

    public void inflate(Activity activity, int LayoutResource, android.support.v7.app.ActionBar getActionBar, String actionBarTitle){
        CoordinatorLayout coordinatorLayout = (CoordinatorLayout) activity.findViewById(R.id.coordinator);
        android.view.LayoutInflater inflater = (android.view.LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View contentView = inflater.inflate(LayoutResource, null, false);

        //change i so that it suits the child number in you coordinator layout
        int i = 1;
        coordinatorLayout.removeViewAt(i);
        coordinatorLayout.addView(contentView, i);
        getActionBar.setTitle(actionBarTitle);
    }

}

Now on the other activities all you have to do is extend the MainActivity and call this method and give it the necessary parameters: 现在,在其他活动中,您需要做的就是扩展MainActivity并调用此方法并为其提供必要的参数:

public class AnotherActivity extends MainActivity {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        new MyLayoutInflater().inflate(this,R.layout.content_activity_another, getSupportActionBar(), getIntent());

    }
}

Ok here is hacky way to do this, I use it only for special kind of debug build to set properties of views in realtime (design tool). 好的,这是hacky方法,我只使用它来进行特殊的调试构建,以实时设置视图的属性(设计工具)。

It has advantage that you can use your child activities as usual without, special behavior that is required in different answers. 它具有以下优势: 您可以像往常一样使用您的孩子活动,而不是在不同答案中需要的特殊行为。

so in BaseActvity you can add: 所以在BaseActvity中你可以添加:

@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);

// WARNING: Hacky, use carefully!!!
ViewGroup androidBaseView = (ViewGroup) findViewById(android.R.id.content);
//this one in what child activity has just set in setContentView()
ViewGroup childContent = (ViewGroup) androidBaseView.getChildAt(0);

View drawerView = LayoutInflater.from(this)
    .inflate(R.layout.base_activity_drawer, androidBaseView, false);
FrameLayout frameLayout = (FrameLayout) drawerView.findViewById(R.id.content);
androidBaseView.removeView(childContent);
frameLayout.addView(childContent);
androidBaseView.addView(drawerView);
}

and xml for drawer is just: 和抽屉的xml只是:

  <android.support.v4.widget.DrawerLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/nav_drawer"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:fitsSystemWindows="true">
  <FrameLayout
    android:id="@+id/content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
  <LinearLayout
    android:id="@+id/drawer_for_components"
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="end"
    android:orientation="vertical"
    android:fitsSystemWindows="true"
    />
</android.support.v4.widget.DrawerLayout>

Here is a simple and fast way to do it in android studio: 这是在android studio中执行此操作的简单快捷方式:

  1. Create a new activity (Navigation drawer activity) from the gallery, and name it whatever you want, android studio will create everything for you (the class and the xml files that you can customize it later) 从库中创建一个新活动(导航抽屉活动),并将其命名为您想要的任何内容,android studio将为您创建所有内容(稍后可以自定义的类和xml文件)

  2. In other activities you should extend your Navigation drawer activity, and make sure these other activities has "no action bar" in the manifests file (android:theme="@style/AppTheme.NoActionBar") 在其他活动中,您应该扩展您的导航抽屉活动,并确保这些其他活动在清单文件中有“无操作栏”(android:theme =“@ style / AppTheme.NoActionBar”)

  3. You should modify your other activities as follows: 您应该修改您的其他活动,如下所示:

     public class Mainactivity extends NavActivity { super.onCreate(savedInstanceState); LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); //inflate your activity layout here! View contentView = inflater.inflate(R.layout.activity_main, null, false); drawer.addView(contentView, 0); } 

Note: the mainactivity will extend the action bar of the NavActivity, the NavActivity has a full functional action bar that will call the navigation drawer 注意:mainactivity将扩展NavActivity的操作栏,NavActivity有一个完整的功能操作栏,可以调用导航抽屉

I hope it will work with you 我希望它能与你合作

Nowadays you should use Single-Activity App Architecture ( source ). 现在您应该使用单活动应用程序架构 )。

Then simple add Navigation Drawer to Main Activity 然后简单地将导航抽屉添加到主要活动

you can simply use <include/> By creating a nav drawer你可以简单地使用<include/>通过创建一个导航抽屉

 <?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">

and then include the layout in it然后在其中包含布局

    <include
        layout="@layout/activity_accounts"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

in your main activity make setContentView(R.layout.your_drawer_activity)在您的主要活动中制作setContentView(R.layout.your_drawer_activity)

take note that if you use this method you have to create a nav drawer layout for every activity you have, unless you found a way to do includes programmatically.请注意,如果您使用此方法,则必须为您拥有的每个活动创建一个导航抽屉布局,除非您找到了一种以编程方式执行包含的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM