2015-10-05 40 views
36

IntelliJ ha apportato modifiche al modello del cassetto di navigazione Attività in Android Studio con meno righe di codice nella classe Attività. La nuova classe di attività si presenta così:Passaggio tra Fragments con onNavigationItemSelezionato nel nuovo modello Activity Navigation Drawer (Android Studio 1.4 in poi)

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 dei più notevole cambiamento qui è il metodo:

onNavigationItemSelected(MenuItem item)

definizione del vecchio modello di navigazione cassetto di questo metodo è stato:

onNavigationItemSelected(int position, long itemId)

È possibile modificare il modello precedente eliminando l'interno.210 di classe, creare i propri frammenti e layout e fare qualcosa di simile:

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

} 

Ma questo non funziona con il nuovo modello (almeno non dalla mia poca conoscenza). Ho provato:

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

ma la disposizione per il layout home è anche mostrato nel layout news. Questo è probabilmente accadendo a causa della linea:

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

dovrebbero Frammenti di essere sostituito in una e il vecchio layout di FrameLayout navigazione cassetto si presentava così:

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

Ma il nuovo uno assomiglia a questo:

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

Per farla breve, come si può modificare il nuovo modello per poter passare da Frammenti?

risposta

69

Quindi, in base alla risposta di @ LL sono stato in grado di risolvere questo problema .

Prima di tutto, aggiungere il FrameLayout al file content_main.xml:

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

Nella tua MainActivity (o quello che hai nominato l'attività con il cassetto di navigazione) definire un metodo denominato 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); 

} 

Sto passando da 3 frammenti personalizzati; NewsFragment, EventsFragment and GalleryFragment.

nel mio menù activity_main_drawer ho cambiato il contenuto a questo:

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

Tornando alla Classe di attività, nella vostra onNavigationItemSelected metodo fare questo:

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

Infine, l'ultima istruzione nel tuo metodo onCreate:

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

Questo perché voglio la prima vista che il mio utente vede essere News.Change a qualunque cosa tu scelga.

maniglia posteriore stampa evento:

Così com'è, se si preme il pulsante indietro da uno qualsiasi dei frammenti, i exits.I app vogliono la mia app per tornare alle News Fragment (il mio frammento di casa) quando l'utente preme il pulsante Indietro. Quindi ho fatto questo:

dichiarato una variabile booleana:

private boolean viewIsAtHome; 

poi nel metodo displayView() ho fatto questo:

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; 

Infine, eliminare il vecchio metodo di onBackPressed e creare un nuovo uno come questo all'esterno il metodo 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 
    } 
} 

Funziona per me.

+1

buon lavoro .. molto molto utile..grazie –

+1

Grazie signore. Ha funzionato per me. – Roon13

+1

Molto semplice e chiaro! Grazie ! – Nekfeu

0

Non so se sarò in grado di aiutare, ma se si desidera modificare i modelli di layout per NavigationDrawerActivity, si può trovare in <Path\to\Program_Files>\Android\Android Studio\plugins\android\lib\templates\activities\NavigationDrawerActivity\root\res\layout

credo, sarà meglio avere un layout simile al seguente -

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

E questo funzionerà con il modo in cui si stava sostituendo le Fragment s in R.id.container precedenza.

+0

Non è il layout che voglio change.I vuole aggiungere le mie frammenti e navigare a loro dal cassetto di navigazione. –

0

Ho utilizzato anche un modello creato automaticamente da Android Studio 1.4 e ho riscontrato le stesse difficoltà.

In primo luogo, ho cambiato 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 che contiene due parti:

  1. schermata principale (LinearLayout)
  2. il cassetto (NavigationView)

schermata principale contiene ActionBar e FrameLayout (R.id.content) saranno sostituiti da un frammento. Il cassetto contiene l'intestazione e il menu.

Così, ora sovrascriviamo suNavigationItemSelected e sostituiamo R.id.content con un frammento.

Ecco il mio codice 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; 
} 

pagina principale è anche un frammento. E ho impostato la pagina principale nel metodo onCreate anche se non sono sicuro se c'è un modo migliore per configurare la pagina principale.

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

PS. ecco il toolbar.xml, l'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> 
10

Non si dovrebbe cambiare il DrawerLayout, è sufficiente aggiungere una cornice nella "content_main.xml".

Seguire le istruzioni riportate di seguito:

  1. aprire il file "content_main.xml" che si trova nella cartella "layout".

  2. utilizzare il codice qui sotto:

    <?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. passare al metodo 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; 
    } 
    
+1

Thanks.Placing the FrameLayout in content_main è stato il principale cambiamento di cui avevo bisogno. –

3

un altro modo è:

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

E poi avrete bisogno di implemts tutti i frammenti per la vostra attività. Nel mio caso si tratta di

MainActivity.java

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

E per gestire l'eccezione che viene gettato nel file di java frammento

"must implement OnFragmentInteractionListener" 

è sufficiente aggiungere sotto metodo

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

E ci sei! Tutto pronto

Thanks to this Tutorial to strike this

Problemi correlati