Cajón de navegación con cabeceras / secciones

Me gustaría saber si hay alguna manera que puedo agregar encabezados / secciones en el cajón de navegación. Me las arreglé para añadir algo así, pero sólo se muestra en la parte superior de la lista, ya que addHeaderView necesita ser llamado antes de setAdapter y si intento agregar más elementos después de setAdapter que volverá a escribir los primeros elementos.

Gracias.

Editar:

public class MenuListAdapter extends BaseAdapter { // Declare Variables Context context; String[] mTitle; String[] mSubTitle; int[] mIcon; LayoutInflater inflater; public MenuListAdapter(Context context, String[] title, String[] subtitle, int[] icon) { this.context = context; this.mTitle = title; this.mSubTitle = subtitle; this.mIcon = icon; inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getViewTypeCount() { return super.getViewTypeCount(); } @Override public int getItemViewType(int position) { return super.getItemViewType(position); } @Override public int getCount() { return mTitle.length; } @Override public Object getItem(int position) { return mTitle[position]; } @Override public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { // Declare Variables TextView txtTitle; TextView txtSubTitle; ImageView imgIcon; View itemView = inflater.inflate(R.layout.drawer_list_item, parent, false); // Locate the TextViews in drawer_list_item.xml txtTitle = (TextView) itemView.findViewById(R.id.title); txtSubTitle = (TextView) itemView.findViewById(R.id.subtitle); // Locate the ImageView in drawer_list_item.xml imgIcon = (ImageView) itemView.findViewById(R.id.icon); // Set the results into TextViews txtTitle.setText(mTitle[position]); txtSubTitle.setText(mSubTitle[position]); // Set the results into ImageView imgIcon.setImageResource(mIcon[position]); return itemView; } 

}

EDITAR:

He encontrado una buena solución mediante la combinación de soluciones de diferentes fuentes, estas son las principales clases que he utilizado:

EntryAdapter

 import java.util.ArrayList; import android.content.Context; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; import com.androidbegin.sidemenututorial.R; public class EntryAdapter extends ArrayAdapter<Item> { private enum RowType { LIST_ITEM, HEADER_ITEM } private Context context; private ArrayList<Item> items; private LayoutInflater vi; public EntryAdapter(Context context, ArrayList<Item> items) { super(context,0, items); this.context = context; this.items = items; vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getViewTypeCount() { //Returns the number of types of Views that will be created by getView(int, View, ViewGroup). return RowType.values().length; } @Override public int getItemViewType(int position) { //framework calls getItemViewType for row n, the row it is about to display. //Get the type of View that will be created by getView(int, View, ViewGroup) for the specified item. Log.i("LIST", "item at " + position + " is " + ((getItem(position).isSection() ? 0 : 1) == 0 ? "section" : "normal item")); return getItem(position).isSection() ? 0 : 1; // get position passes (n) and accertain is its a header or not } @Override public boolean isEnabled(int position) { return !getItem(position).isSection(); } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; final Item i = items.get(position); if (i != null) { if(i.isSection()){ SectionItem si = (SectionItem) i; v = vi.inflate(R.layout.list_item_section, null); v.setOnClickListener(null); v.setOnLongClickListener(null); v.setLongClickable(false); final TextView sectionView = (TextView) v.findViewById(R.id.list_item_section_text); sectionView.setText(si.getTitle()); }else{ EntryItem ei = (EntryItem) i; v = vi.inflate(R.layout.list_item_entry, null); final TextView title = (TextView)v.findViewById(R.id.list_item_entry_title); final TextView subtitle = (TextView)v.findViewById(R.id.list_item_entry_summary); if (title != null) title.setText(ei.title); if(subtitle != null) subtitle.setText(ei.subtitle); } } return v; } } 

EntryItem

 public class EntryItem implements Item{ public final String title; public final String subtitle; public EntryItem(String title, String subtitle) { this.title = title; this.subtitle = subtitle; } @Override public boolean isSection() { return false; } } 

ít.

 public interface Item { public boolean isSection(); } 

SecciónItem

 public class SectionItem implements Item{ private final String title; public SectionItem(String title) { this.title = title; } public String getTitle(){ return title; } @Override public boolean isSection() { return true; } } 

Actividad principal

 import java.util.ArrayList; import android.content.Context; import android.content.res.Configuration; import android.os.Bundle; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.Toast; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; import com.androidbegin.item.EntryAdapter; import com.androidbegin.item.EntryItem; import com.androidbegin.item.Item; import com.androidbegin.item.SectionItem; public class MainActivity extends SherlockFragmentActivity { // Declare Variable DrawerLayout mDrawerLayout; ListView mDrawerList; ActionBarDrawerToggle mDrawerToggle; MenuListAdapter mMenuAdapter; String[] title; String[] subtitle; int[] icon; Fragment fragment1 = new Fragment1(); Fragment fragment2 = new Fragment2(); Fragment fragment3 = new Fragment3(); Context context; ArrayList<Item> items = new ArrayList<Item>(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.drawer_main); this.context = this; // Generate title title = new String[] { "Title Fragment 1", "Title Fragment 2", "Title Fragment 3" }; // Generate subtitle subtitle = new String[] { "Subtitle Fragment 1", "Subtitle Fragment 2", "Subtitle Fragment 3" }; // Generate icon icon = new int[] { R.drawable.action_about, R.drawable.action_settings, R.drawable.collections_cloud }; // Locate DrawerLayout in drawer_main.xml mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); // Locate ListView in drawer_main.xml mDrawerList = (ListView) findViewById(R.id.left_drawer); // Set a custom shadow that overlays the main content when the drawer // opens mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); // Pass results to MenuListAdapter Class // mMenuAdapter = new MenuListAdapter(this, title, subtitle, icon); // Set the MenuListAdapter to the ListView // mDrawerList.setAdapter(mMenuAdapter); items.add(new SectionItem("Category 1")); items.add(new EntryItem("Item 1", "This is item 1.1")); items.add(new EntryItem("Item 2", "This is item 1.2")); items.add(new EntryItem("Item 3", "This is item 1.3")); items.add(new SectionItem("Category 2")); items.add(new EntryItem("Item 4", "This is item 2.1")); items.add(new EntryItem("Item 5", "This is item 2.2")); items.add(new EntryItem("Item 6", "This is item 2.3")); items.add(new EntryItem("Item 7", "This is item 2.4")); items.add(new SectionItem("Category 3")); items.add(new EntryItem("Item 8", "This is item 3.1")); items.add(new EntryItem("Item 9", "This is item 3.2")); items.add(new EntryItem("Item 10", "This is item 3.3")); items.add(new EntryItem("Item 11", "This is item 3.4")); items.add(new EntryItem("Item 12", "This is item 3.5")); EntryAdapter adapter = new EntryAdapter(this, items); mDrawerList.setAdapter(adapter); // Capture button clicks on side menu mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); // Enable ActionBar app icon to behave as action to toggle nav drawer getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true); // ActionBarDrawerToggle ties together the the proper interactions // between the sliding drawer and the action bar app icon mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) { public void onDrawerClosed(View view) { // TODO Auto-generated method stub super.onDrawerClosed(view); } public void onDrawerOpened(View drawerView) { // TODO Auto-generated method stub super.onDrawerOpened(drawerView); } }; mDrawerLayout.setDrawerListener(mDrawerToggle); if (savedInstanceState == null) { selectItem(0); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getSupportMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { if (mDrawerLayout.isDrawerOpen(mDrawerList)) { mDrawerLayout.closeDrawer(mDrawerList); } else { mDrawerLayout.openDrawer(mDrawerList); } } return super.onOptionsItemSelected(item); } // The click listener for ListView in the navigation drawer private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Log.i("LIST", "item position = " + Integer.toString(position) + "\nitem id = " + String.valueOf(id)); if (!items.get(position).isSection()) { EntryItem item = (EntryItem)items.get(position); Toast.makeText(context, "You clicked " + item.title , Toast.LENGTH_SHORT).show(); selectItem(position); } // selectItem(position); } } private void selectItem(int position) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); // Locate Position switch (position) { case 0: ft.replace(R.id.content_frame, fragment1); break; case 1: ft.replace(R.id.content_frame, fragment2); break; case 2: ft.replace(R.id.content_frame, fragment3); break; } ft.commit(); mDrawerList.setItemChecked(position, true); // Close drawer mDrawerLayout.closeDrawer(mDrawerList); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); // Sync the toggle state after onRestoreInstanceState has occurred. mDrawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Pass any configuration change to the drawer toggles mDrawerToggle.onConfigurationChanged(newConfig); } } 

Pero tengo un pequeño problema: las secciones toman una posición en la lista y la selección de fragmentos está desordenada.

Agregue encabezados / secciones a un ListView para usarlo en un DrawerLayout la misma manera que agrega encabezados / secciones a ListView para usar en cualquier otro lugar dentro de Android.

En el nivel bajo, esto implica un ListAdapter que:

  • getViewTypeCount() para indicar cuántos tipos distintos de filas hay (por ejemplo, 2, uno para los encabezados y otro para las filas regulares)

  • getItemViewType() para indicar qué tipo de fila se utiliza para una position determinada

  • Asegura que getView() (o newView() / bindView() de un CursorAdapter ) es consciente de los múltiples tipos de fila y los procesa en consecuencia

En un nivel superior, puede intentar utilizar cosas como mi MergeAdapter , o varias otras bibliotecas de terceros, para ayudar a simplificar esto.

En la gaveta de navegación, la lista de elementos se puede mostrar usando un ListView para que pueda tener un adaptador de clase e implementar su lógica. Así que puede agregar secciones, encabezados y así sucesivamente.

Aquí usted tiene un ejemplo completo del cajón de la navegación que usa cabeceras / secciones

Este es el resultado

Introduzca aquí la descripción de la imagen

Si los elementos de la lista son fijos (no cambia), un "hack" rápido sería incluir una caja de conmutación para "posición" en el método getView () del adaptador e inflar un headerlayout.xml en esas posiciones fijas. Su inflación regular entrará en la parte por defecto de la caja del interruptor. Es sucio y no es recomendable pero efectivo.

Sugiero extender EntryItem añadiendo un miembro de etiqueta que le indique qué tipo de fragmento crear. A continuación, solo marque la etiqueta en su manejador onItemClick para crear el tipo correcto de fragmento. De esta manera no depende de la posición, que puede cambiar a medida que agrega o quita elementos en las secciones.

Debe agregar esto a la clase EntryAdapter:

 @Override public boolean areAllItemsEnabled () { return false; } 

Con eso, y:

 @Override public boolean isEnabled(int position) { return !getItem(position).isSection(); } 

Las secciones no deben tomar una posición en el ListView.

Una buena solución que leí era colocar una cabecera TextView dentro de su archivo de disposición de fila y establecer su visibilidad a GONE .

Entonces, en el getView su adaptador, tiene alguna lógica que dice: ¿Es este el primer elemento de la lista (posición 0), O es el tipo de este elemento diferente del tipo una posición por encima? Si es así, gire la visibilidad TextView's la cabecera a VISIBLE .

Esta manera es preferida porque cuando usted desea utilizar getItemAtPosition , usted no tiene que calcular hacia fuera cómo esquivar sus cabeceras de la sección mientras que tomarían una posición entera si usted los implementó la manera el OP y otros sugirieron.

  • El cajón de navegación se cerrará incluso si se sobreescribe OnBackPressed ()
  • ¿Cómo puedo hacer que el cajón de navegación no cierre completamente el cajón izquierdo?
  • Ver Gone cuando se hace clic fuera de esa vista
  • Cómo agregar iconos adyacentes a los títulos de Android Navigation Drawer
  • Cómo deslizar el ActionBar junto con el NavigationDrawer
  • El efecto de sombra superpuesto permanece en NavigationView del cajón de navegación
  • Prueba de interfaz de usuario de Robotium para la aplicación con el cajón de navegación
  • ¿En qué componentes de interfaz de usuario deben utilizarse los filtros y / o la clasificación?
  • El artículo de DrawerLayout hace clic - ¿Cuándo es el momento adecuado para reemplazar el fragmento?
  • Cajón de navegación de derecha a izquierda con v7 ActionBarDrawerToggle
  • Utilizar smoothScrollTo en Fragmento
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.