[英]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: 请按照以下步骤操作:
open the "content_main.xml" file located in the "layout" folder. 打开位于“layout”文件夹中的“content_main.xml”文件。
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>
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 搞定
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.container
的Fragment
的方式一起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
包含两部分:
LinearLayout
) 主屏幕( LinearLayout
) 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();
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.