在新的导航抽屉活动模板中使用onNavigationItemSelected在片段之间切换(Android Studio 1.4及更高版本)

问题描述:

IntelliJ更改了Android Studio中导航抽屉模板的Activity,而Activity类中的代码行却减少了.新的Activity类如下所示:

IntelliJ has made changes to the Navigation Drawer template Activity in Android Studio with fewer lines of code in the Activity class. The new Activity class looks like this:

public class MainActivity extends AppCompatActivity
    implements NavigationView.OnNavigationItemSelectedListener {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
            this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.setDrawerListener(toggle);
    toggle.syncState();

    NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
    navigationView.setNavigationItemSelectedListener(this);
}

@Override
public void onBackPressed() {
    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    if (drawer.isDrawerOpen(GravityCompat.START)) {
        drawer.closeDrawer(GravityCompat.START);
    } else {
        super.onBackPressed();
    }
}


@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
    // Handle navigation view item clicks here.
    int id = item.getItemId();

    if (id == R.id.nav_camara) {
        // Handle the camera action
    } else if (id == R.id.nav_gallery) {

    } else if (id == R.id.nav_slideshow) {

    } else if (id == R.id.nav_manage) {

    } else if (id == R.id.nav_share) {

    } else if (id == R.id.nav_send) {

    }

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.closeDrawer(GravityCompat.START);
    return true;
}
}

最显着的变化之一是方法:

One of the most notable change here is the method:

onNavigationItemSelected(MenuItem item)

此方法的旧导航抽屉模板的定义为:

The old Navigation Drawer template's definition of this method was:

onNavigationItemSelected(int position, long itemId)

您可以通过删除内部的PlaceHolderFragment类,创建自己的片段和布局并执行以下操作来修改旧模板:

You could modify that old template by deleting the inner PlaceHolderFragment class, creating your own fragments and layouts and doing something like this:

Fragment fragment = null;
switch (position) {
    case 0:
        fragment = new FragmentA();
        break;
    case 1:
        fragment = new FragmentB();
        break;
    default:
        break;
}

if (fragment != null) {
    FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager.beginTransaction()
            .replace(R.id.frame_container, fragment).commit();

}

但这不适用于新模板(至少据我所知不是这样).我已经尝试过:

But this doesn't work with the new template (at least not from my little knowledge). I have tried:

 public boolean onNavigationItemSelected(MenuItem item) {
    // Handle navigation view item clicks here.
    int id = item.getItemId();
    Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), item.getTitle() + " clicked", Snackbar.LENGTH_SHORT);
    Fragment fragment = null;
    switch (id) {
        case R.id.nav_home:
            fragment = HomeFragment.getFragInstance();
            break;

        case R.id.nav_news:

            fragment = NewsFragment.getFragInstance();
            break;


        default:
            break;
    }

    if (fragment != null) {
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.addToBackStack(null);
        transaction.replace(R.id.drawer_layout, fragment);
        transaction.commit();


        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);

    }
    return true;
}

,但是home布局的布局也显示在news布局中. 这可能是由于以下原因导致的:

but the layout for the home layout is also shown in the news layout. This is probably happening because of the line:

transaction.replace(R.id.drawer_layout, fragment);

应该在FrameLayout中替换片段,并且旧的导航抽屉布局看起来像这样:

Fragments are supposed to be replaced in a FrameLayout and the old Navigation Drawer layout looked like this:

<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 to display Fragments -->
<FrameLayout
    android:id="@+id/frame_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<!-- Listview to display slider menu -->


<ListView
    android:id="@+id/list_sliderMenu"
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:choiceMode="singleChoice"
    android:divider="@color/white"
    android:dividerHeight="1dp"
    android:listSelector="@drawable/list_selector"
    android:background="@color/list_background"/>

但是新的看起来像这样:

But the new one looks like this:

 <?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"
   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_base"
    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_base"
    app:menu="@menu/activity_base_drawer" />

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

长话短说,如何修改新模板以能够在片段之间切换?

Long story short, how can one modify the new template to be able to switch between Fragments?

因此,基于@ L.L.的回答,我能够解决此问题.

So, based on @L.L.'s answer I was able to solve this problem.

首先,将您的FrameLayout添加到您的content_main.xml文件中:

First of all, add your FrameLayout to your content_main.xml file:

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

在您的MainActivity(或您在导航抽屉中已命名为活动"的任何东西)中,定义一个名为displayView

In your MainActivity (or whatever you have named the Activity with the navigation drawer) define a method named displayView

 public void displayView(int viewId) {

    Fragment fragment = null;
    String title = getString(R.string.app_name);

    switch (viewId) {
        case R.id.nav_news:
            fragment = new NewsFragment();
            title  = "News";

            break;
        case R.id.nav_events:
            fragment = new EventsFragment();
            title = "Events";
            break;

    }

    if (fragment != null) {
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.content_frame, fragment);
        ft.commit();
    }

    // set the toolbar title
    if (getSupportActionBar() != null) {
        getSupportActionBar().setTitle(title);
    }

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.closeDrawer(GravityCompat.START);

}

Am在3个自定义片段之间切换; NewsFragment,EventsFragment和GalleryFragment.

Am switching between 3 custom Fragments; NewsFragment, EventsFragment and GalleryFragment.

在我的菜单activity_main_drawer中,我已将内容更改为此:

in my menu activity_main_drawer I have changed the content to this:

<menu xmlns:android="http://schemas.android.com/apk/res/android">

<group android:checkableBehavior="single">
    <item android:id="@+id/nav_news"  
        android:icon="@android:drawable/ic_menu_news"
        android:title="News" />
    <item android:id="@+id/nav_events" 
        android:icon="@android:drawable/ic_menu_events"
        android:title="Events" />
    <item android:id="@+id/nav_gallery" 
        android:icon="@android:drawable/ic_menu_gallery"
        android:title="Gallery" />
  </group>
</menu>

返回您的onNavigationItemSelected方法中的Activity类 做到这一点:

Going back to the Activity class, in your onNavigationItemSelected method do this:

@Override
public boolean onNavigationItemSelected(MenuItem item) {
    displayView(item.getItemId());
    return true;
}

最后,您的onCreate方法中的最后一条语句:

Finally, the last statement in your onCreate method:

 @Override
protected void onCreate(Bundle savedInstanceState) {
    ....
    ....
    displayView(R.id.nav_news);
}

这是因为我希望用户看到的第一个视图是新闻",将其更改为您选择的任何内容.

This is because I want the first view my user sees to be News.Change it to whatever you choose.

处理后退新闻事件:

按现状显示,如果您从任何片段"中按后退"按钮,则应用程序退出.当用户按下后退"按钮时,我希望我的应用程序返回到新闻片段"(我的主片段).所以我这样做了:

As it stands, if you press the back button from any of the Fragments, the app exits.I want my app to go back to the News Fragment (my home fragment) when the user presses the back button. So I did this:

声明了一个布尔变量:

private boolean viewIsAtHome;

然后在displayView()方法中执行以下操作:

then in the displayView() method I did this:

 public void displayView(int viewId){
    Fragment fragment = null;
    String title = getString(R.string.app_name);

    switch (viewId) {
        case R.id.nav_news:
            fragment = new NewsFragment();
            title  = getString(R.string.news_title);
            viewIsAtHome = true;

            break;
        case R.id.nav_events:
            fragment = new EventsFragment();
            title = getString(R.string.events_title);
            viewIsAtHome = false;
            break;

        case R.id.nav_gallery:
            fragment = new GalleryFragment();
            title = getString(R.string.gallery_title);
            viewIsAtHome = false;
            break;

最后,删除旧的onBackPressed方法,并在onCreate()方法的外部处创建一个新的方法:

Finally, delete your old onBackPressed method and create a new one like this outside the onCreate() method:

@Override
public void onBackPressed() {
    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    if (drawer.isDrawerOpen(GravityCompat.START)) {
        drawer.closeDrawer(GravityCompat.START);
    }
    if (!viewIsAtHome) { //if the current view is not the News fragment
        displayView(R.id.nav_news); //display the News fragment
    } else {
        moveTaskToBack(true);  //If view is in News fragment, exit application
    }
}

为我工作.