简体   繁体   English

在新的导航抽屉活动模板中使用onNavigationItemSelected在片段之间切换(Android Studio 1.4以后)

[英]Switch between Fragments with onNavigationItemSelected in new Navigation Drawer Activity template (Android Studio 1.4 onward)

IntelliJ has made changes to the Navigation Drawer template Activity in Android Studio with fewer lines of code in the Activity class. IntelliJ在Android Studio中对Navigation Drawer模板Activity进行了更改,Activity类中的代码行更少。 The new Activity class looks like this: 新的Activity类如下所示:

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: 旧的Navigation Drawer模板对此方法的定义是:

onNavigationItemSelected(int position, long itemId)

You could modify that old template by deleting the inner PlaceHolderFragment class, creating your own fragments and layouts and doing something like this: 您可以通过删除内部PlaceHolderFragment类来修改该旧模板,创建自己的片段和布局,并执行以下操作:

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

but the layout for the home layout is also shown in the news layout. 但是home布局的布局也显示在news布局中。 This is probably happening because of the line: 这可能是因为这条线:

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

Fragments are supposed to be replaced in a FrameLayout and the old Navigation Drawer layout looked like this: 片段应该在FrameLayout替换,旧的Navigation Drawer布局如下所示:

<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? 长话短说,如何修改新模板才能在片段之间切换?

So, based on @LL's answer I was able to solve this problem. 所以,基于@LL的答案,我能够解决这个问题。

First of all, add your FrameLayout to your content_main.xml file: 首先,将FrameLayout添加到content_main.xml文件中:

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

In your MainActivity (or whatever you have named the Activity with the navigation drawer) define a method named displayView MainActivity (或者您使用导航抽屉命名Activity的任何内容)定义名为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 switching between 3 custom Fragments; 我在3个自定义碎片之间切换; NewsFragment, EventsFragment and GalleryFragment. NewsFragment,EventsFragment和GalleryFragment。

in my menu activity_main_drawer I have changed the content to this: 在我的菜单activity_main_drawer我已将内容更改为:

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

Going back to the Activity class, in your onNavigationItemSelected method do this: 回到Activity类,在onNavigationItemSelected方法中执行以下操作:

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

Finally, the last statement in your onCreate method: 最后,你的onCreate方法中的最后一个语句:

 @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. 这是因为我希望我的用户看到的第一个视图是News.Change它为您选择的任何内容。

Handle back press event: 处理新闻事件:

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: 所以我这样做了:

Declared a boolean variable: 声明了一个布尔变量:

private boolean viewIsAtHome;

then in the displayView() method I did this: 然后在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  = 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;

Finally, delete your old onBackPressed method and create a new one like this outside the onCreate() method: 最后,删除旧的onBackPressed方法并在onCreate()方法之外创建一个这样的新方法:

@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
    }
}

Works for me. 适合我。

You should not change the DrawerLayout , you only need to add a frame in the "content_main.xml". 您不应该更改DrawerLayout ,只需要在“content_main.xml”中添加一个框架。

Follow the steps below: 请按照以下步骤操作:

  1. open the "content_main.xml" file located in the "layout" folder. 打开位于“layout”文件夹中的“content_main.xml”文件。

  2. use the code below: 使用以下代码:

     <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:showIn="@layout/app_bar_main" tools:context=".MainActivity"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/mainFrame"> </FrameLayout> </RelativeLayout> 
  3. go to the onNavigationItemSelected method: 转到onNavigationItemSelected方法:

     public boolean onNavigationItemSelected(MenuItem item) { int id = item.getItemId(); Fragment fragment; if (id == R.id.nav_camara) { fragment = new YourFragment(); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.mainFrame, fragment); ft.commit(); } 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; } 

another way is: 另一种方式是:

public boolean onNavigationItemSelected(MenuItem item) {
    // Handle navigation view item clicks here.
    Fragment fragment;
    int id = item.getItemId();

    if (id == R.id.nav_camera) {
        // Handle the camera action
        fragment = new BlankFragment();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.container_new, fragment);
        ft.commit();
    } else if (id == R.id.nav_gallery) {
        fragment = new HorizontalView();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.container_new,fragment);
        ft.commit();
    } else if (id == R.id.nav_slideshow) {
        fragment = new FragmentVerticleView();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.container_new,fragment);
        ft.commit();

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

And then you'll need to implemts all the fragments to your activity. 然后,您需要将所有片段实现到您的活动中。 In my case it's 就我而言,它是

MainActivity.java MainActivity.java

    public class MainActivity extends AppCompatActivity
    implements BlankFragment.OnFragmentInteractionListener, HorizontalView.OnFragmentInteractionListener,FragmentVerticleView.OnFragmentInteractionListener,OnNavigationItemSelectedListener
     { 
    //coding stuff
    }

And to handle the Exception that is Thrown in fragment java file 并处理片段java文件中抛出的异常

    "must implement OnFragmentInteractionListener"

you simply add below method 你只需添加以下方法

      public void    onFragmentInteraction(Uri uri){
    //We can keep this empty
}

And there you go! 你去吧! All set 搞定

Thanks to this Tutorial to strike this 感谢这个教程打击这个

Not sure if I'll be able to help, but if you want to modify the layout templates for NavigationDrawer Activity , you can find it in <Path\\to\\Program_Files>\\Android\\Android Studio\\plugins\\android\\lib\\templates\\activities\\NavigationDrawerActivity\\root\\res\\layout 不确定我是否能够提供帮助,但是如果你想修改NavigationDrawer Activity的布局模板,你可以在<Path\\to\\Program_Files>\\Android\\Android Studio\\plugins\\android\\lib\\templates\\activities\\NavigationDrawerActivity\\root\\res\\layout找到它<Path\\to\\Program_Files>\\Android\\Android Studio\\plugins\\android\\lib\\templates\\activities\\NavigationDrawerActivity\\root\\res\\layout

I believe, it will be best to have a layout similar to the following - 我相信,最好有一个类似于以下的布局 -

<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}">

    <!-- As the main content view, the view below consumes the entire
         space available using match_parent in both dimensions. -->
    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- android:layout_gravity="start" tells DrawerLayout to treat
         this as a sliding drawer on the left side for left-to-right
         languages and on the right side for right-to-left languages.
         If you're not building against API 17 or higher, use
         android:layout_gravity="left" instead. -->
    <!-- The drawer is given a fixed width in dp and extends the full height of
         the container. -->
    <NavigationView android:id="@+id/navigation_drawer"
        android:layout_width="@dimen/navigation_drawer_width"
        android:layout_height="match_parent"
        android:layout_gravity="<#if buildApi gte 17>start<#else>left</#if>" />

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

And this will work with the way you were replacing the Fragment s in R.id.container earlier. 这将与您之前更换R.id.containerFragment的方式一起R.id.container

I used a template auto-created by Android Studio 1.4 too, and I had encounter same difficulties as you. 我使用了Android Studio 1.4自动创建的模板,我遇到了和你一样的困难。

First, I changed activity_main.xml 首先,我更改了activity_main.xml

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

<!--Main-->
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <!-- The ActionBar -->
    <include
        layout="@layout/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <FrameLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </FrameLayout>
</LinearLayout>

<!--Drawer-->
<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"
    app:menu="@menu/drawer" /></android.support.v4.widget.DrawerLayout>

A DrawerLayout that contains two parts: DrawerLayout包含两部分:

  1. Main Screen ( LinearLayout ) 主屏幕( LinearLayout
  2. the Drawer ( NavigationView ) 抽屉( NavigationView

Main Screen contains the ActionBar and the FrameLayout ( R.id.content ) will be replaced by a fragment. 主屏幕包含ActionBar,FrameLayout( R.id.content )将被片段替换。 The Drawer contains the header and the menu. 抽屉包含标题和菜单。

So, we now override onNavigationItemSelected and replace R.id.content with a fragment. 因此,我们现在覆盖onNavigationItemSelected并用片段替换R.id.content

Here is my MainActivity code: 这是我的MainActivity代码:

    @Override
public boolean onNavigationItemSelected(MenuItem item) {
    Fragment fragment;
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    // Handle navigation view item clicks here.
    int id = item.getItemId();

    if (id == R.id.nav_A) {
        fragment = new AFragment();
        ft.replace(R.id.content, fragment).commit();        
    } else if (id == R.id.nav_B){
        fragment = new BFragment();
        ft.replace(R.id.content, fragment).commit();
    } else if (id == R.id.nav_settings) {
        Intent intent = new Intent(MainActivity.this, SettingsActivity.class);
        startActivity(intent);
    }

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

Main page is also a fragment. 主页也是一个片段。 And I set up main page in onCreate method although I am not sure if there is a better way to set up main page. 我在onCreate方法中设置主页,虽然我不确定是否有更好的方法来设置主页面。

//MainPageFragment
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    ft.replace(R.id.content, new MainPageFragment()).commit();

PS. PS。 here is the toolbar.xml , the ActionBar 这是toolbar.xml ,ActionBar

<?xml version="1.0" encoding="utf-8"?>
<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" android:fitsSystemWindows="true"
tools:context="jean.yang.MainActivity">
<android.support.design.widget.AppBarLayout android:layout_height="wrap_content"
    android:layout_width="match_parent" 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>
</android.support.design.widget.CoordinatorLayout>

Try to remove previous fragment or remove all history than add fresh fragment. 尝试删除以前的片段或删除所有历史记录而不是添加新片段。

//Here we are clearing back stack fragment entries
int backStackEntry = getSupportFragmentManager().getBackStackEntryCount();
if (backStackEntry > 0) {
    for (int i = 0; i < backStackEntry; i++) {
        getSupportFragmentManager().popBackStackImmediate();
    }
}

//Here we are removing all the fragment that are shown here
if (getSupportFragmentManager().getFragments() != null && getSupportFragmentManager().getFragments().size() > 0) {
    for (int i = 0; i < getSupportFragmentManager().getFragments().size(); i++) {
        Fragment mFragment = getSupportFragmentManager().getFragments().get(i);
        if (mFragment != null) {
            getSupportFragmentManager().beginTransaction().remove(mFragment).commit();
        }
    }
}

More help from here 从这里获得更多帮助

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

相关问题 如何在默认Android Studio导航抽屉中的片段之间切换 - How to switch between Fragments in default Android Studio Navigation Drawer Android Studio 1.4中的导航抽屉模板 - Navigation drawer template in Android Studio 1.4 在Android Studio的默认导航抽屉模板中使用按钮在片段之间切换 - Switching between fragments with a button in default Navigation Drawer template of Android Studio 如何修复 Android studio 3.5 导航活动模板 onNavigationItemSelected 不起作用 - How to fix Android studio 3.5 navigation activity template onNavigationItemSelected not working Android Studio 1.4导航抽屉 - Android Studio 1.4 Navigation Drawer 如何在导航抽屉活动模板中的片段之间传递字符串变量 - How to pass string variable between fragments in navigation drawer activity template 新设计中的Android switch Fragments支持导航抽屉 - Android switch Fragments in the new design support navigation drawer 使用onNavigationItemSelected()在导航抽屉中切换片段 - Switching Fragments in navigation drawer using onNavigationItemSelected() 如何通过导航抽屉切换片段(Android的新支持库)? - How to Switch Fragments by Navigation Drawer (new support library by android)? Android Studio 1.4 新抽屉模板中的渲染问题 - Android Studio 1.4 Rendering Problems In New Drawer Template
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM