不同活动中的相同导航抽屉

MEX*_*MEX 198 navigation android drawer android-activity navigation-drawer

我制作了一个工作的导航抽屉,就像它在developer.android.com网站上的教程中所示.但现在,我想使用一个导航抽屉,我在NavigationDrawer.class中为我的应用程序中的多个活动创建.

我的问题是,如果这里有人可以制作一个小教程,这解释了如何使用一个导航抽屉进行多个活动.

在多个活动的答案Android导航抽屉上首先阅读了它

但它对我的项目不起作用

public class NavigationDrawer extends Activity {
public DrawerLayout drawerLayout;
public ListView drawerList;
private ActionBarDrawerToggle drawerToggle;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawerToggle = new ActionBarDrawerToggle((Activity) this, drawerLayout, R.drawable.ic_drawer, 0, 0) {

        public void onDrawerClosed(View view) {
            getActionBar().setTitle(R.string.app_name);
        }

        public void onDrawerOpened(View drawerView) {
            getActionBar().setTitle(R.string.menu);
        }
    };
    drawerLayout.setDrawerListener(drawerToggle);

    getActionBar().setDisplayHomeAsUpEnabled(true);
    getActionBar().setHomeButtonEnabled(true);

    layers = getResources().getStringArray(R.array.layers_array);
    drawerList = (ListView) findViewById(R.id.left_drawer);
    View header = getLayoutInflater().inflate(R.layout.drawer_list_header, null);
    drawerList.addHeaderView(header, null, false);
    drawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, android.R.id.text1,
            layers));
    View footerView = ((LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
            R.layout.drawer_list_footer, null, false);
    drawerList.addFooterView(footerView);

    drawerList.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3) {
            map.drawerClickEvent(pos);
        }
    });
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    if (drawerToggle.onOptionsItemSelected(item)) {
        return true;
    }
    return super.onOptionsItemSelected(item);

}

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

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    drawerToggle.onConfigurationChanged(newConfig);
}
}
Run Code Online (Sandbox Code Playgroud)

在这个活动中,我希望有导航抽屉,所以我扩展了'NavigationDrawer',在其他一些活动中,我希望用户使用相同的导航抽屉

  public class SampleActivity extends NavigationDrawer {...}
Run Code Online (Sandbox Code Playgroud)

我不知道要改变什么......

Kev*_*rlo 183

如果您想要导航抽屉,则应使用片段.我上周遵循了这个教程,效果很好:

http://developer.android.com/training/implementing-navigation/nav-drawer.html

您还可以从本教程下载示例代码,以了解如何执行此操作.


没有片段:

这是您的BaseActivity代码:

public class BaseActivity extends Activity
{
    public DrawerLayout drawerLayout;
    public ListView drawerList;
    public String[] layers;
    private ActionBarDrawerToggle drawerToggle;
    private Map map;

    protected void onCreate(Bundle savedInstanceState)
    {
        // R.id.drawer_layout should be in every activity with exactly the same id.
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

        drawerToggle = new ActionBarDrawerToggle((Activity) this, drawerLayout, R.drawable.ic_drawer, 0, 0) 
        {
            public void onDrawerClosed(View view) 
            {
                getActionBar().setTitle(R.string.app_name);
            }

            public void onDrawerOpened(View drawerView) 
            {
                getActionBar().setTitle(R.string.menu);
            }
        };
        drawerLayout.setDrawerListener(drawerToggle);

        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);

        layers = getResources().getStringArray(R.array.layers_array);
        drawerList = (ListView) findViewById(R.id.left_drawer);
        View header = getLayoutInflater().inflate(R.layout.drawer_list_header, null);
        drawerList.addHeaderView(header, null, false);
        drawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, android.R.id.text1,
                layers));
        View footerView = ((LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
                R.layout.drawer_list_footer, null, false);
        drawerList.addFooterView(footerView);

        drawerList.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3) {
                map.drawerClickEvent(pos);
            }
        });
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        if (drawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        return super.onOptionsItemSelected(item);

    }

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

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        drawerToggle.onConfigurationChanged(newConfig);
    }
}
Run Code Online (Sandbox Code Playgroud)

需要具有导航抽屉的所有其他活动应该扩展此活动而不是活动本身,例如:

public class AnyActivity extends BaseActivity
{
    //Because this activity extends BaseActivity it automatically has the navigation drawer
    //You can just write your normal Activity code and you don't need to add anything for the navigation drawer
}
Run Code Online (Sandbox Code Playgroud)

XML

<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" >
        <!-- Put what you want as your normal screen in here, you can also choose for a linear layout or any other layout, whatever you prefer -->
    </FrameLayout>
    <!-- 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="#111"/>
</android.support.v4.widget.DrawerLayout>
Run Code Online (Sandbox Code Playgroud)

编辑:

我自己遇到了一些困难,所以如果你得到NullPointerExceptions,这里有一个解决方案.在BaseActivity中,将onCreate函数更改为protected void onCreateDrawer().其余的可以保持不变.在扩展BaseActivity的活动中,按以下顺序放置代码:

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity);
    super.onCreateDrawer();
Run Code Online (Sandbox Code Playgroud)

这有助于我解决我的问题,希望它有所帮助!

如果您有任何问题可以随意提问,这就是您可以创建具有多个活动的导航抽屉的方法.


编辑2:

正如@GregDan所说,你BaseActivity也可以覆盖setContentView()并调用onCreateDrawer:

@Override 
public void setContentView(@LayoutRes int layoutResID) 
{ 
    super.setContentView(layoutResID); 
    onCreateDrawer() ;
}
Run Code Online (Sandbox Code Playgroud)

  • 对于任何相当复杂的应用程序而言,只有一个Activity可能是一项艰巨的任务.使用活动可以从系统中获得大量免费内容 - 因此如何使用多个活动是一个有效的方法.我无法想象一个Activity处理任意数量的片段组合之间的通信 - 它只是不起作用. (131认同)
  • 我不想在片段上使用活动,我只想使用使用所有相同导航抽屉的不同活动.我想要活动,因为我可以使用不同类型的布局,如滑动视图,地图视图...... (7认同)
  • @KevinvanMierlo你能告诉我你的意思:R.id.drawer_layout应该在每个具有完全相同id的活动中.因为我完全按照你在这里所说的做了,我在扩展这个BaseActivity的Activity的onCreate()方法中得到了一个N​​ullPointerException. (2认同)

Win*_*der 34

我发现了最好的实现.它位于Google I/O 2014应用程序中.

他们使用与凯文相同的方法.如果您可以从I/O应用程序中的所有不需要的东西中抽象出自己,那么您可以提取所需的一切,并且Google确保它正确使用导航抽屉模式.每个活动可选地具有DrawerLayout作为其主要布局.有趣的是如何完成导航到其他屏幕.它是这样实现的BaseActivity:

private void goToNavDrawerItem(int item) {
        Intent intent;
        switch (item) {
            case NAVDRAWER_ITEM_MY_SCHEDULE:
                intent = new Intent(this, MyScheduleActivity.class);
                startActivity(intent);
                finish();
                break;
Run Code Online (Sandbox Code Playgroud)

这与通过片段事务替换当前片段的常见方式不同.但是用户没有发现视觉差异.


Mic*_*cro 7

对于任何想要做原始海报所要求的人,请考虑使用片段而不是凯文所说的方式.这是一个关于如何做到这一点的优秀教程:

https://github.com/codepath/android_guides/wiki/Fragment-Navigation-Drawer

如果您选择使用活动而不是片段,则每次导航到新活动时都会遇到导航抽屉被重新创建的问题.这导致每次导航抽屉的丑陋/慢速渲染.


jwe*_*rle 7

所以这个答案是迟了几年但有人可能会欣赏它.Android为我们提供了一个新的小部件,可以更轻松地使用一个导航抽屉和多个活动.

android.support.design.widget.NavigationView是模块化的,在菜单文件夹中有自己的布局.您使用它的方式是以下列方式包装xml布局:

  1. Root Layout是一个android.support.v4.widget.DrawerLayout,它包含两个子节点:一个<include ... />用于包装的布局(参见2)和一个android.support.design.widget.NavigationView.

    <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">
    
    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    
    <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" />
    
    Run Code Online (Sandbox Code Playgroud)

nav_header_main只是一个LinearLayout,其orientationInd为vertical,用于导航Drawar的标题.

activity_main_drawer是res/menu目录中的菜单xml.它可以包含您选择的项目和组.如果您使用AndroidStudio图库,向导将为您制作一个基本的向导,您可以看到您的选项.

  1. 应用程序栏布局现在通常是android.support.design.widget.CoordinatorLayout,这将包括两个子项:android.support.design.widget.AppBarLayout(其中包含android.support.v7.widget.Toolbar)和一个<include ... >for你的实际内容(见3).

    <android.support.design.widget.CoordinatorLayout
        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="yourpackage.MainActivity">
    
     <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" />
    
    Run Code Online (Sandbox Code Playgroud)

  2. 内容布局可以是您想要的任何布局.这是包含活动主要内容的布局(不包括导航抽屉或应用栏).

现在,关于所有这些的很酷的事情是你可以在这两个布局中包装每个活动但是让你的NavigationView(参见步骤1)始终指向activity_main_drawer(或其他).这意味着您将在所有活动中使用相同的(*)导航抽屉.

  • 它们不是NavigationView 的相同实例,但公平地说,即使使用上面概述的BaseActivity解决方案也是如此.


Abh*_*ena 5

我的建议是:根本不使用活动,而是使用片段,并在显示第一个片段的容器(例如,线性布局)中替换它们.

该代码在Android Developer Tutorials中提供,您只需自定义即可.

http://developer.android.com/training/implementing-navigation/nav-drawer.html

建议您在应用程序中使用越来越多的片段,应用程序本地应该只有四个基本活动,您在AndroidManifest.xml中提到的除外部活动之外(例如FacebookActivity):

  1. SplashActivity:不使用片段,并使用FullScreen主题.

  2. LoginSignUpActivity:根本不需要NavigationDrawer,也不需要后退按钮,所以只需使用普通工具栏,但至少需要3或4个片段.使用no-action-bar主题

  3. HomeActivity或DashBoard活动:使用无操作栏主题.在这里,您需要导航抽屉,随后的所有屏幕都将是片段或嵌套片段,直到叶子视图,与共享抽屉.在此活动中,所有设置,用户配置文件等都将作为片段.此处的片段不会添加到后堆栈中,而是会从抽屉菜单项中打开.对于需要后退按钮而不是抽屉的碎片,下面有第四种活动.

  4. 活动没有抽屉.此活动在顶部有一个后退按钮,内部的片段将共享相同的操作栏.这些片段将被添加到后台,因为会有导航历史记录.

[有关进一步指导,请参阅:https://stackoverflow.com/a/51100507/787399 ]

快乐编码!!


Lev*_*yan 5

在一组活动中重用公共导航抽屉的最简单方法

app_base_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

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

    </FrameLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:menu="@menu/menu_test"
        />
</android.support.v4.widget.DrawerLayout>
Run Code Online (Sandbox Code Playgroud)

AppBaseActivity.java

/*
* This is a simple and easy approach to reuse the same 
* navigation drawer on your other activities. Just create
* a base layout that conains a DrawerLayout, the 
* navigation drawer and a FrameLayout to hold your
* content view. All you have to do is to extend your 
* activities from this class to set that navigation 
* drawer. Happy hacking :)
* P.S: You don't need to declare this Activity in the 
* AndroidManifest.xml. This is just a base class.
*/
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

public abstract class AppBaseActivity extends AppCompatActivity implements MenuItem.OnMenuItemClickListener {
    private FrameLayout view_stub; //This is the framelayout to keep your content view
    private NavigationView navigation_view; // The new navigation view from Android Design Library. Can inflate menu resources. Easy
    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mDrawerToggle;
    private Menu drawerMenu;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.app_base_layout);// The base layout that contains your navigation drawer.
        view_stub = (FrameLayout) findViewById(R.id.view_stub);
        navigation_view = (NavigationView) findViewById(R.id.navigation_view);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, 0, 0);
        mDrawerLayout.setDrawerListener(mDrawerToggle);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        drawerMenu = navigation_view.getMenu();
        for(int i = 0; i < drawerMenu.size(); i++) {
          drawerMenu.getItem(i).setOnMenuItemClickListener(this);
        }
        // and so on...
    }

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

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

    /* Override all setContentView methods to put the content view to the FrameLayout view_stub
     * so that, we can make other activity implementations looks like normal activity subclasses.
     */
    @Override
    public void setContentView(int layoutResID) {
        if (view_stub != null) {
            LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT);
            View stubView = inflater.inflate(layoutResID, view_stub, false);
            view_stub.addView(stubView, lp);
        }
    }

    @Override
    public void setContentView(View view) {
        if (view_stub != null) {
            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT);
            view_stub.addView(view, lp);
        }
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        if (view_stub != null) {
            view_stub.addView(view, params);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Pass the event to ActionBarDrawerToggle, if it returns
        // true, then it has handled the app icon touch event
        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        // Handle your other action bar items...

        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.item1:
                // handle it
                break;
            case R.id.item2:
                // do whatever
                break;
            // and so on...
        }
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)