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

我制作了一个工作的抽屉,就像在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); } } 

在这个活动,我想有导航抽屉,所以我扩展了“NavigationDrawer”,在其他一些活动,我想用户相同的导航抽屉

  public class SampleActivity extends NavigationDrawer {...} 

我不知道要改变什么

如果你想要一个导航抽屉,你应该使用碎片。 我上个礼拜跟着这个教程,效果很好:

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); } } 

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

 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 } 

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> 

编辑:

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

  super.onCreate(savedInstanceState); setContentView(R.layout.activity); super.onCreateDrawer(); 

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

如果您有任何问题可以随意问,那么您可以创建一个具有多个活动的导航抽屉。


编辑2:

正如@GregDan所说,你的BaseAcivity也可以覆盖setContentView()并在那里调用onCreateDrawer:

 @Override public void setContentView(@LayoutRes int layoutResID) { super.setContentView(layoutResID); onCreateDrawer() } 

我找到了最好的实现。 它在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; 

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

有一个工作:在我的实现:我有片段在第一个活动有导航抽屉。 其他活动使用与第一个活动相同的代码创建ActionBar和Navigation Drawer,并且它们没有碎片,布局在后面描述。 在第一个活动中,项目的动作点击是在同一活动中处理的,在其他活动中,动作稍后完成,首先通过关闭其他活动切换到第一个活动。 条件如下:

  1. 我已经把主布局和里面的第一个framelayout,第二个framelayout是专门在DrawerLayout中的抽屉。

  2. 我在第一个活动以外的活动的onResume中完成了抽屉初始化。 这是因为它需要在新的意图更新之后重新初始化,因为所有的活动都是单个实例。

这样我就可以在所有的活动中有NavigationDrawer和ActionBarCompat。

对于想要做什么原始海报要求的人,请考虑使用片段,而不是凯文说的方式。 这里是一个很好的教程,如何做到这一点:

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

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

在baseactivity中更新这个代码。 并且不要忘记在你的activity xml中包含drawer_list_header。

 super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); setContentView(R.layout.drawer_list_header); 

并且不要在你的活动中使用request()。 但仍然抽屉是不可见的点击图像..拖动它将可见没有列表项目。 我尝试了很多,但没有成功。 需要一些锻炼…

用@Kevin van Mierlo的回答,你也可以实现几个抽屉。 例如,位于左侧的默认菜单(开始)以及位于右侧的另一个可选菜单,仅当加载了确定片段时才显示。

我已经能够做到这一点。

 package xxxxxx; import android.app.SearchManager; import android.content.Context; import android.content.Intent; import android.widget.SearchView; 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.os.Bundle; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; public class loginhome extends AppCompatActivity { private Toolbar toolbar; private NavigationView navigationView; private DrawerLayout drawerLayout; // Make sure to be using android.support.v7.app.ActionBarDrawerToggle version. // The android.support.v4.app.ActionBarDrawerToggle has been deprecated. private ActionBarDrawerToggle drawerToggle; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.loginhome); // Initializing Toolbar and setting it as the actionbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); //Initializing NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); //Setting Navigation View Item Selected Listener to handle the item click of the navigation menu navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { // This method will trigger on item Click of navigation menu public boolean onNavigationItemSelected(MenuItem menuItem) { //Checking if the item is in checked state or not, if not make it in checked state if(menuItem.isChecked()) menuItem.setChecked(false); else menuItem.setChecked(true); //Closing drawer on item click drawerLayout.closeDrawers(); //Check to see which item was being clicked and perform appropriate action switch (menuItem.getItemId()){ //Replacing the main content with ContentFragment Which is our Inbox View; case R.id.nav_first_fragment: Toast.makeText(getApplicationContext(),"First fragment",Toast.LENGTH_SHORT).show(); FirstFragment fragment = new FirstFragment(); android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.replace(R.id.frame,fragment); fragmentTransaction.commit(); return true; // For rest of the options we just show a toast on click case R.id.nav_second_fragment: Toast.makeText(getApplicationContext(),"Second fragment",Toast.LENGTH_SHORT).show(); SecondFragment fragment2 = new SecondFragment(); android.support.v4.app.FragmentTransaction fragmentTransaction2 = getSupportFragmentManager().beginTransaction(); fragmentTransaction2.replace(R.id.frame,fragment2); fragmentTransaction2.commit(); return true; default: Toast.makeText(getApplicationContext(),"Somethings Wrong",Toast.LENGTH_SHORT).show(); return true; } } }); // Initializing Drawer Layout and ActionBarToggle drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.drawer_open, R.string.drawer_close){ @Override public void onDrawerClosed(View drawerView) { // Code here will be triggered once the drawer closes as we dont want anything to happen so we leave this blank super.onDrawerClosed(drawerView); } @Override public void onDrawerOpened(View drawerView) { // Code here will be triggered once the drawer open as we dont want anything to happen so we leave this blank super.onDrawerOpened(drawerView); } }; //Setting the actionbarToggle to drawer layout drawerLayout.setDrawerListener(actionBarDrawerToggle); //calling sync state is necessay or else your hamburger icon wont show up actionBarDrawerToggle.syncState(); } 

使用这个为你的toolbar.xml

 <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorPrimary" android:elevation="4dp" android:id="@+id/toolbar" android:theme="@style/ThemeOverlay.AppCompat.Dark" > </android.support.v7.widget.Toolbar> 

如果要使用,则将其用于导航标题

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="192dp" android:background="?attr/colorPrimaryDark" android:padding="16dp" android:theme="@style/ThemeOverlay.AppCompat.Dark" android:orientation="vertical" android:gravity="bottom"> <LinearLayout android:layout_width="match_parent" android:layout_height="56dp" android:id="@+id/navhead" android:orientation="vertical" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:textColor="#ffffff" android:text="tanya" android:textSize="14sp" android:textStyle="bold" /> <TextView android:id="@+id/email" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ffffff" android:layout_marginLeft="16dp" android:layout_marginTop="5dp" android:text="tanya.com" android:textSize="14sp" android:textStyle="normal" /> </LinearLayout> <de.hdodenhof.circleimageview.CircleImageView android:layout_width="70dp" android:layout_height="70dp" android:layout_below="@+id/imageView" android:layout_marginTop="15dp" android:src="@drawable/face" android:id="@+id/circleView" /> </RelativeLayout> 

我在Kotlin这样做:

 open class BaseAppCompatActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener { protected lateinit var drawerLayout: DrawerLayout protected lateinit var navigationView: NavigationView @Inject lateinit var loginService: LoginService override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Log.d("BaseAppCompatActivity", "onCreate()") App.getComponent().inject(this) drawerLayout = findViewById(R.id.drawer_layout) as DrawerLayout val toolbar = findViewById(R.id.toolbar) as Toolbar setSupportActionBar(toolbar) navigationView = findViewById(R.id.nav_view) as NavigationView navigationView.setNavigationItemSelectedListener(this) val toggle = ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) drawerLayout.addDrawerListener(toggle) toggle.syncState() toggle.isDrawerIndicatorEnabled = true val navigationViewHeaderView = navigationView.getHeaderView(0) navigationViewHeaderView.login_txt.text = SharedKey.username } private inline fun <reified T: Activity> launch():Boolean{ if(this is T) return closeDrawer() val intent = Intent(applicationContext, T::class.java) startActivity(intent) finish() return true } private fun closeDrawer(): Boolean { drawerLayout.closeDrawer(GravityCompat.START) return true } override fun onNavigationItemSelected(item: MenuItem): Boolean { val id = item.itemId when (id) { R.id.action_tasks -> { return launch<TasksActivity>() } R.id.action_contacts -> { return launch<ContactActivity>() } R.id.action_logout -> { createExitDialog(loginService, this) } } return false } } 

抽屉的活动必须继承这个BaseAppCompatActivity ,在设置内容(实际上可以移动到某个init方法)之后调用super.onCreate ,并且在其布局中有相应的ID元素

所以这个答案是晚了几年,但有人可能会感激。 Android给了我们一个新的小部件,使得使用一个导航抽屉与几个活动更容易。

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

  1. 根布局是一个包含两个子项的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" /> 

nav_header_main只是一个LinearLayout,导航Drawar的标题为orientation = vertical。

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

  1. 应用栏布局现在通常是一个android.support.design.widget.CoordinatorLayout,这将包括两个孩子:一个android.support.design.widget.AppBarLayout(其中包含一个android.support.v7.widget.Toolbar)和一个<include ... >为您的实际内容(见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" /> 
  2. 内容布局可以是任何你想要的布局。 这是包含活动主要内容的布局(不包括导航抽屉或应用栏)。

现在,关于这一切的最酷的事情是你可以将这两个布局中的每个活动包装起来,但是你的NavigationView(见步骤1)总是指向activity_main_drawer(或其他)。 这意味着您将在所有活动中使用相同的(*)导航抽屉。

  • 他们不会是NavigationView的同一个实例 ,但公平地说,即使使用上面提到的BaseActivity解决方案也是不可能的。

使用片段在您的MainActivity中创建导航抽屉。
在MainActivity中初始化导航抽屉
现在在所有其他活动中,您要使用相同的导航抽屉将DrawerLayout作为基础和片段作为导航抽屉。 只需在您的片段中设置android:name指向您的片段Java文件。 您不需要在其他活动中初始化片段。
您可以通过在Google Play商店应用中进行的其他活动中的滑动来访问导航器抽屉