the - navigationview android
Alternar entre fragmentos con onNavigationItemSelected en la nueva plantilla de actividad del cajón de navegación(Android Studio 1.4 en adelante) (5)
Entonces, basado en la respuesta de @ LL, pude resolver este problema.
En primer lugar, agregue su FrameLayout a su archivo content_main.xml
:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" android:id="@+id/content_frame"/>
En su MainActivity
(o como se llame la Actividad con el cajón de navegación) defina un método llamado 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);
}
Estoy cambiando entre 3 Fragmentos personalizados; NoticiasFragmento, EventosFragmento y GaleríaFragmento.
en mi menu activity_main_drawer
he cambiado el contenido a esto:
<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>
Volviendo a la clase de actividad, en su método onNavigationItemSelected
haga esto:
@Override
public boolean onNavigationItemSelected(MenuItem item) {
displayView(item.getItemId());
return true;
}
Finalmente, la última declaración en su método onCreate:
@Override
protected void onCreate(Bundle savedInstanceState) {
....
....
displayView(R.id.nav_news);
}
Esto se debe a que quiero que la primera vista que vea mi usuario sea Noticias. Cámbiela a lo que elija.
Manejar atrás evento de prensa:
Tal como está, si presiona el botón Atrás desde cualquiera de los Fragmentos, la aplicación sale. Quiero que mi aplicación regrese al Fragmento de Noticias (mi fragmento de inicio) cuando el usuario presione el botón Atrás. Así que hice esto:
Declarada una variable booleana:
private boolean viewIsAtHome;
Luego en el método displayView()
hice esto:
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;
Finalmente, elimine su antiguo método onBackPressed
y cree uno nuevo como este fuera del método 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
}
}
Funciona para mi.
IntelliJ ha realizado cambios en la actividad de la plantilla de Navigation Drawer en Android Studio con menos líneas de código en la clase de actividad. La nueva clase de actividad se ve así:
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;
}
}
Uno de los cambios más notables aquí es el método:
onNavigationItemSelected(MenuItem item)
La definición de este método de la vieja plantilla de Navigation Drawer era:
onNavigationItemSelected(int position, long itemId)
Puedes modificar esa plantilla antigua eliminando la clase interna PlaceHolderFragment
, creando tus propios fragmentos y diseños y haciendo algo como esto:
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();
}
Pero esto no funciona con la nueva plantilla (al menos no por mi poco conocimiento). Yo he tratado:
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;
}
pero el diseño para el diseño de home
también se muestra en el diseño de news
. Esto probablemente está sucediendo debido a la línea:
transaction.replace(R.id.drawer_layout, fragment);
Se supone que los fragmentos deben reemplazarse en un FrameLayout
y el diseño anterior del cajón de navegación tenía este aspecto:
<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"/>
Pero el nuevo se ve así:
<?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>
En pocas palabras, ¿cómo se puede modificar la nueva plantilla para poder cambiar entre Fragmentos?
No debe cambiar DrawerLayout
, solo necesita agregar un marco en el "content_main.xml".
Siga los pasos a continuación:
abra el archivo "content_main.xml" ubicado en la carpeta "layout".
Usa el siguiente código:
<?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>
vaya al método
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; }
No estoy seguro de si podré ayudar, pero si desea modificar las plantillas de diseño para la Activity
NavigationDrawer
, puede encontrarlas en <Path/to/Program_Files>/Android/Android Studio/plugins/android/lib/templates/activities/NavigationDrawerActivity/root/res/layout
Creo que será mejor tener un diseño similar al siguiente:
<!-- 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>
Y esto funcionará con la forma en que anteriormente reemplazó los Fragment
en el R.id.container
.
También utilicé una plantilla creada automáticamente por Android Studio 1.4 y tuve las mismas dificultades que tú.
Primero, cambié 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>
Un DrawerLayout
que contiene dos partes:
- Pantalla principal (
LinearLayout
) - el cajón (
NavigationView
)
La pantalla principal contiene la barra de acción y el FrameLayout ( R.id.content
) se reemplazará por un fragmento. El cajón contiene el encabezado y el menú.
Por lo tanto, ahora reemplazamos onNavigationItemSelected y reemplazamos R.id.content
con un fragmento.
Aquí está mi código de 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;
}
La página principal también es un fragmento. Y configuro la página principal en el método onCreate
, aunque no estoy seguro de si hay una mejor manera de configurar la página principal.
//MainPageFragment
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.content, new MainPageFragment()).commit();
PD. Aquí está la toolbar.xml
, la barra de acción
<?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>
otra forma es
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;
}
Y luego deberá implementar todos los fragmentos de su actividad. En mi caso es
MainActivity.java
public class MainActivity extends AppCompatActivity
implements BlankFragment.OnFragmentInteractionListener, HorizontalView.OnFragmentInteractionListener,FragmentVerticleView.OnFragmentInteractionListener,OnNavigationItemSelectedListener
{
//coding stuff
}
Y para manejar la excepción que es lanzada en el fragmento de archivo java.
"must implement OnFragmentInteractionListener"
simplemente agrega el siguiente método
public void onFragmentInteraction(Uri uri){
//We can keep this empty
}
¡Y ahí tienes! Todo listo