2014-10-25 15 views
32

Secondo the Material Design specs la larghezza del Nav cassetto su dispositivi mobili deve essereMaterial Design: Nav cassetto Larghezza

lato width nav = larghezza dello schermo - applicazione altezza della barra

Come facciamo a implementare questo su Android ?

Ho due soluzioni parziali. Il primo è il modo hacky: nell'attività contenente metto questo codice:

 
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB_MR1) { 
    final Display display = getWindowManager().getDefaultDisplay(); 
    final Point size = new Point(); 
    display.getSize(size); 

    final ViewGroup.LayoutParams params = mDrawerFragment.getView().getLayoutParams(); 
    params.width = size.x - getResources().getDimensionPixelSize(
     R.dimen.abc_action_bar_default_height_material 
    ); 
    mFragmentUserList.getView().setLayoutParams(params); 
}

Questo, tuttavia, provoca un secondo ciclo di layout e non funziona in gingerbread: non è ottimale.

La seconda soluzione prevede l'aggiunta di uno spazio tra il frammento e il cassettoLayout. Tuttavia, sposta l'ombra e il punto in cui l'utente può premere per tornare all'app principale. Si blocca anche quando si preme l'icona "hamburguer". Neanche ottimale.

Esiste una soluzione migliore, preferibilmente una che include stili e xml?

risposta

23

Con il Android Design Support Library ora è molto semplice da implementare cassetto navigazione compreso corretto dimensionamento. Usa lo NavigationView e usa la sua capacità di estrarre il cassetto dalla risorsa del menu (esempio here) oppure puoi semplicemente avvolgerlo intorno alla vista che usi attualmente per mostrare l'elenco dei tuoi cassetti (ad esempio ListView, RecyclerView). NavigationView si prenderà quindi cura del dimensionamento del cassetto per te.

Ecco un esempio di come io uso la NavigationView avvolto intorno ListView:

<?xml version="1.0" encoding="utf-8"?> 
<android.support.v4.widget.DrawerLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:id="@+id/navdrawer_layout" 
    android:fitsSystemWindows="true"> 

    <!-- Layout where content is shown --> 
    <RelativeLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

     <include android:id="@+id/toolbar" 
      layout="@layout/toolbar" /> 

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

     <!-- Toolbar shadow for pre-lollipop --> 
     <View style="@style/ToolbarDropshadow" 
      android:layout_width="match_parent" 
      android:layout_height="3dp" 
      android:layout_below="@id/toolbar" /> 

    </RelativeLayout> 

    <android.support.design.widget.NavigationView 
     android:id="@+id/navigation_view" 
     android:layout_width="wrap_content" 
     android:layout_height="match_parent" 
     android:layout_gravity="start"> 

     <ListView 
      android:id="@+id/navdrawer_list" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      android:choiceMode="singleChoice" 
      android:dividerHeight="0dp" 
      android:divider="@null"/> 

    </android.support.design.widget.NavigationView> 

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

In questo modo è possibile utilizzare NavigationViews dimensionamento e ancora usare la vostra lista cassetto. Anche se è molto più semplice creare l'elenco dei cassetti dalla risorsa del menu (esempio here) non è possibile utilizzare le visualizzazioni personalizzate per gli elementi dell'elenco.

+0

Questo funziona abbastanza bene per me. Penso che questa dovrebbe essere la risposta corretta, in quanto non richiede sforzi di programmazione da parte dello sviluppatore. Eppure, in grado di riempire completamente le linee guida sulla larghezza del cassetto di navigazione di Google. –

+0

@logan: hai ragione. Ma questa era una domanda che precede l'era materiale ... – zubietaroberto

+0

@zubietaroberto Sì, certo, lo so. Ma potrebbe ancora esserci qualcuno che ha problemi con questo tipo di problema e potrebbe trovarlo utile. – Logan

32

Sono riuscito a creare una soluzione utilizzando dichiarazioni di stile XML ma è anche un po 'hacky. Il mio approccio era usare i margini invece di applicare una larghezza impostata per evitare di scrivere qualsiasi codice per calcolare manualmente il layout. Ho creato una regola di base per evidenziare come farlo funzionare.

Sfortunatamente, DrawerLayout applica attualmente un margine minimo di 64dp. Affinché questo approccio funzioni, dobbiamo compensare tale valore con margini negativi in ​​modo da ottenere la larghezza desiderata per il cassetto di navigazione. Speriamo che questo possa essere risolto in futuro (Someone has filed an issue regarding it) in modo che possiamo solo fare riferimento al riferimento alla dimensione abc_action_bar_default_height_material per il margine.

procedere come segue:

  1. aggiungere le seguenti definizioni delle dimensioni e stile:

    valori/dimens.xml

    <!-- Match 56dp default ActionBar height on portrait orientation --> 
    <dimen name="nav_drawer_margin_offset">-8dp</dimen> 
    

    valori-land/dimens. xml

    <!-- Match 48dp default ActionBar height on landscape orientation --> 
    <dimen name="nav_drawer_margin_offset">-16dp</dimen> 
    

    valori/styles.xml

    <!-- Nav drawer style to set width specified by Material Design specification --> 
    <style name="NavDrawer"> 
        <item name="android:layout_width">match_parent</item> 
        <item name="android:layout_marginRight">@dimen/nav_drawer_margin_offset</item> 
    </style> 
    

    valori-sw600dp/styles.xml

    <!-- Margin already matches ActionBar height on tablets, just modify width --> 
    <style name="NavDrawer"> 
        <item name="android:layout_width">320dp</item> 
        <item name="android:layout_marginRight">0dp</item> 
    </style> 
    
  2. Dopo aver aggiunto le regole di cui sopra nel progetto, è può fare riferimento allo stile NavDrawer nel cassetto di navigazione visualizza:

    layout/navigation_drawer.xml (o altra vista appropriata utilizzati per il cassetto di navigazione)

    <?xml version="1.0" encoding="utf-8"?> 
    <ListView xmlns:android="http://schemas.android.com/apk/res/android" 
        android:id="@+id/navigation_drawer" 
        style="@style/NavDrawer" 
        android:layout_height="match_parent" 
        android:layout_gravity="start" 
        android:choiceMode="singleChoice" 
        android:divider="@android:color/transparent" 
        android:dividerHeight="0dp" 
        android:background="#FFF" 
    /> 
    
+2

Dovrebbe essere accettato come risposta, questa informazione è fantastica. Grazie uomo. – MiguelCatalan

8

Dopo ricerca di una soluzione più semplice, ho trovato un articolo molto chiarire: Material Navigation Drawer sizing.

Qui:

Lo schermo Nexus 5 è un bel 640 x 360 dp (xxhdpi), ed una barra app su è alto 56 dp. Così il cassetto nav dovrebbe essere:

[larghezza in dp] = 360dp - 56dp =

schermo invece 304dp

un Nexus 4 sfoggia un 640 x 384 dp (xhdpi). Stessa altezza della barra delle applicazioni 56dp. Il suo cassetto nav?

[larghezza in dp] = 384dp - 56dp = 328dp

Quindi, come hanno fatto i progettisti di Google venire con 288dp e 304dp larghezze rispettivamente? Non ne ho idea.

Le app di Google, su d'altra parte, sembrano essere d'accordo con la mia matematica. Oh, e sai qual è la cosa più divertente di ? L'iPhone (che ha diverse altezze dello schermo , ma una larghezza costante di 320 dp) è contrassegnato correttamente come avente un cassetto nav 264dp nav.

In sostanza, mostra che alcune linee guida circa il cassetto di navigazione si contraddicono e che è possibile utilizzare la seguente regola per evitare calcoli:

si può sostanzialmente sempre usare 304dp su -sw360dp e 320dp su -sw384dp per il tuo cassetto di navigazione, e avrai capito bene.

4

Essi specifiche già aggiornati, la società di navigazione larghezza cassetto è:

Math.min(screenWidth — actionBarSize, 6 * actionBarSize); 
+1

"La larghezza della barra laterale è uguale alla larghezza dello schermo meno l'altezza della barra delle azioni, o in questo caso 56dp dal bordo destro dello schermo.La larghezza massima del cassetto nav è 5 volte l'incremento standard (56dp su dispositivo mobile e 64dp su tablet). " Dove stai ricevendo 6 * actionbarSize? – DDukesterman

+0

Sì, si dice 5, ma 5 non sembra giusto, mentre 6 lo fa, sembra un errore nella documentazione. Stavo cercando un modo per inviare questo, ma non riesco a trovarne. – vovkab

+0

Btw, se controlli il loro screenshot e lo misuri, noterai che non è sicuramente 5 :) http://www.google.com/design/spec/patterns/navigation-drawer.html – vovkab

0

Beh ho trovato questo molto difficile da capire e implementare. Sfortunatamente, la soluzione di Matthew ha reso il mio browser nav troppo ampio per il panorama, e sembrava contrario alle pratiche di Google, cioè la larghezza del nav è determinata dalla larghezza più piccola del dispositivo. In ogni caso non funzionerebbe nel mio caso in quanto ho disabilitato la configurazione nel mio manifest. Così ho deciso di modificare dinamicamente la larghezza del nav con il seguente codice.

Va notato che la mia app è solo per telefoni e ho optato per una larghezza massima di 320 dpi. Questo è anche il motivo per cui ho optato per l'altezza della barra degli strumenti 56dp per entrambi gli orientamenti.

Spero che aiuti qualcuno e che possano evitare lo stress inutile che mi ha causato.

navDrawLayout.post(new Runnable() 
    { 

     @Override 
     public void run() { 

      Resources r = getResources(); 

      DisplayMetrics metrics = new DisplayMetrics(); 

      if(r.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){ 

       getWindowManager().getDefaultDisplay().getMetrics(metrics); 
       int height = metrics.heightPixels; 

       float screenWidth = height/r.getDisplayMetrics().density; 
       float navWidth = (screenWidth - 56); 

       navWidth = Math.min(navWidth, 320); 

       int newWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, navWidth, r.getDisplayMetrics()); 

       DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) navDrawLayout.getLayoutParams(); 
       params.width = newWidth; 
       navDrawLayout.setLayoutParams(params);  


      } 

      if(r.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { 

      getWindowManager().getDefaultDisplay().getMetrics(metrics); 
      int width = metrics.widthPixels; 

      float screenWidth = width/r.getDisplayMetrics().density; 
      float navWidth = screenWidth - 56; 

      navWidth = Math.min(navWidth, 320); 

      int newWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, navWidth, r.getDisplayMetrics()); 

      DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) navDrawLayout.getLayoutParams(); 
      params.width = newWidth; 
      navDrawLayout.setLayoutParams(params); 


      } 
     } 

    } 
    ); 
Problemi correlati