domingo, 23 de febrero de 2014

Menús

Los menús son elementos muy habituales en aplicaciones de interfaz gráfico para incorporar acciones adicionales.

Compatibilidad

v1
Desde v11 los dispositivos NO están obligados a disponer de tecla menú por lo que deben utilizar un ActionBar (compatibilidad con versiones inferiores con support.v7)

Lo mínimo necesario

Crear un fichero XML en la ubicación /res/menu:
<?xml version="1.0"encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/file" android:title="@string/file">
<menu>
<item
   android:id="@+id/create_new"
   android:icon="@drawable/new"
   android:showAsAction="true"
   android:title="@string/create_new"/>
<item
   android:id="@+id/open"
   android:title="@string/open"/>
</menu>
</item>
</menu>


Cada elemento viene identificado por un id para referencia desde código, un título y/o imagen y si se indica el atributo showAsAction se mostrará en el ActionBar.
Para cada uno de ellos se puede definir a su vez un submenú.

Sobrescribir el método onCreateOptionsMenu de la Activity para cargar el menú:
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}


Sobrescribir onOptionsItemSelected para atender a los eventos de selección de ítem:
public boolean onOptionsItemSelected(MenuItem item) {
      switch (item.getItemId()) {
      case R.id.menu_actualizar:
            this.actualizar();
            return true;
      case R.id.menu_config:
            this.configurar();
            return true;
...
default:
            return super.onContextItemSelected(item);
}


Menús Contextuales

Un menú contextual se refiere a acciones relacionadas con un componente en concreto del interfaz gráfico. A menudo se asocia con la pulsación larga sobre un elemento o ítem en concreto.
Para ello hay que registrar el componente para mostrar menú contextual:
registerForContextMenu(tvMessage);


Cargar el fichero de menú a través del método onCreateContextMenu:
public void onCreateContextMenu(ContextMenu menu, View v,
                                ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    MenuInflater inflater = getMenuInflater();
    //Cargar fichero concreto en función de la vista seleccionada
 inflater.inflate(R.menu.context_menu, menu);
}


Responder al evento a través del método onContextItemSelected:
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info =
(AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
...


Referencias

https://developer.android.com/training/basics/actionbar/setting-up.html

domingo, 16 de febrero de 2014

Diálogos

Un diálogo es una pequeña ventana que aparece sobre la Activity actual para mostrar información adicional o requerir alguna acción del usuario.

Lo mínimo necesario

Emplear un Builder para construir un AlertDialog:
AlertDialog dialog = new AlertDialog.Builder(this).
                  setTitle("Ejemplo").
                  setMessage("Hola!").
                  setNeutralButton("Cerrar", null).
                  create();

Mostrar el diálogo:
dialog.show();


Opciones adicionales

Definiendo algunas opciones del AlertDialog se puede construir un diálogo con mayores capacidades:
AlertDialog dialog = new AlertDialog.Builder(this)
.setMessage("¿Desea salir de la app?")
.setCancelable(false)
.setPositiveButton("SI", new DialogInterface.OnClickListener() {
      public void onClick(DialogInterface dialog, int id) {
      finish();
      }
})
.setNegativeButton("NO", new DialogInterface.OnClickListener() {
      public void onClick(DialogInterface dialog, int id) {
      dialog.cancel();
      }
});
.create();


Se puede definir también un layout personalizado para el diálogo, de forma que se permitirá cualquier tipo de componente sobre él:
//Pasar fichero de layout (parent=null ya que se carga en el diálogo)
builder.setView(inflater.inflate(R.layout.dialog_signin, null));


Referencias

domingo, 9 de febrero de 2014

Adaptadores

Para los elementos compuestos del interfaz como listas o componentes de selección es necesario emplear adaptadores que proporcionen la información necesaria.

La forma más sencilla de adaptador es emplear un adaptador del sistema empleando recursos estáticos, aunque Android también permite emplear adaptadores personalizados con datos provenientes de orígenes distintos que además son configurables en aspecto y comportamiento.

Lo mínimo necesario

Definir un adaptador para mostrar la información:
ListView listView1 = (ListView) findViewById(R.id.lvLista);
//Datos
String[] items = { "Leche", "Huevos", "Harina" };
       
//Definir y asignar el adaptador
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, items);
listView1.setAdapter(adapter);


También es posible definir los datos en fichero de recursos:
<string-array name="precios">       
       <item>15€/mes</item>
       <item>20€/mes</item>
       <item>Gratuito</item>
</string-array>


El ArrayAdapter para el componente se genera de forma similar:
Spinner sp = (Spinner) findViewById(R.id.spPrecios);
ArrayAdapter<?> adapter = ArrayAdapter.createFromResource(this,
      R.array.precios, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item);

sp.setAdapter(adapter);


Un adaptador NO se restringe simplemente a cadenas de caracteres, se puede definir un adaptador para cualquier clase de la aplicación:
//Se utiliza el método toString de Provincia a la hora de mostrar
ArrayAdapter<Provincia> adapter = new ArrayAdapter<Provincia>(this,
android.R.layout.simple_list_item_1, items);

listView1.setAdapter(adapter);
listView.setOnItemClickListener(new OnItemClickListener(){
  @Override
  public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
    //Obtener la provincia seleccionada
    Provincia p = (Provincia) parent.getAdapter().getItem(position);
    …
  }
});


Adaptadores Personalizados

Se puede generar un adaptador personalizado para representar instancias de objetos que no se limiten simplemente a mostrar el texto representativo, sino que también puedan mostrar otra información de los objetos, modificar la disposición de elementos en pantalla, estilos, …

Definir un ListView dentro del layout de la Activity:
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
       
        <ListView
            android:id="@+id/lvLista"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
        </ListView>
</LinearLayout>


Establecer un layout (list_item) que representa cada uno de los elementos a mostrar:
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:background="@android:color/transparent"
    android:cacheColorHint="@android:color/transparent"
    android:padding="5dp">
   
    <LinearLayout
        android:id="@+id/imgLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_marginRight="5dp"
        android:padding=“3dp">

        <ImageView
            android:id="@+id/ivImagen"
            android:layout_width="50dp"
            android:layout_height="50dp"/>
    </LinearLayout>
   
    <TextView
        android:id="@+id/tvNombre"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:textSize="15dp"
        android:layout_alignTop="@id/imgLayout"
        android:layout_toRightOf=“@id/imgLayout”/>

    <TextView
        android:id="@+id/tvDescripcion"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/tvNombre"
        android:layout_toRightOf="@id/imgLayout"
        android:layout_marginTop="1dip" />
   
</RelativeLayout>


Definir el adaptador de listas para la clase Empleado:
public class EmpleadoAdapter extends ArrayAdapter<Empleado> {
  private ArrayList<Empleado> elementos;
  private Context context;
  private int resourceId;

  public EmpleadoAdapter(Context context, int resourceId,
                  ArrayList<Empleado> elementos) {
super(context, resourceId, elementos);
      this.elementos = elementos;
this.context = context;
this.resourceId = resourceId;
  }

  @Override
  public View getView(int pos, View convertView, ViewGroup parent)
//Evita llamadas innecesarias a findViewById
ViewElemento holder;
// Evitar reinflar los componentes
if (convertView == null) {
  LayoutInflater vi = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = vi.inflate(R.layout.list_item, null);
        holder = new ViewElemento();
        holder.texto =
            (TextView) convertView.findViewById(R.id.tvNombre);
        holder.descripcion =
            (TextView) convertView.findViewById(R.id.tvDescripcion);
        holder.foto =
            (ImageView) convertView.findViewById(R.id.ivImagen);
        convertView.setTag(holder);
      } else {
        holder = (ViewElemento) convertView.getTag();
      }
      Empleado emp = elementos.get(pos);
      if (emp != null) {
        // Construir el elemento
        holder.texto.setText(emp.getNombre()); 
  holder.descripcion.setText(emp.getPuesto());
        holder.foto.setImageDrawable(emp.getFoto());
}
                 
      return convertView;
  }

  public int getCount() {
      return elementos.size();
  }

  public Empleado getItem(int position) {
      return elementos.get(position);
  }

  public long getItemId(int position) {
      return position;
  }

  static class ViewElemento {
      ImageView foto;
      TextView texto;
TextView descripcion;
  }
}

Establecer el adaptador de listas:
listView = (ListView) findViewById(R.id.lvEmpleados);
// Permitir lista con fondo transparente
listView.setCacheColorHint(0);

// Cargar el adaptador de listas
listView.setAdapter(new EmpleadosAdapter(this, R.layout.list_item, lista));

listView.setOnItemClickListener(this);


Referencias