Componentes de Interfaz en Android: Manejo de Listas Desplegables, Selección Múltiple y Eventos de Pulsación Larga

Descripción General

Este artículo aborda el uso de componentes de interfaz de usuario en Android, enfocándose en listas desplegables (Spinner), campos de autocompletado (AutoCompleteTextView) y listas (ListView). Se incluyen ejemplos para escuchar eventos de selección, vincular datos dinámicamente, gestionar selecciones múltiples, menejar pulsaciones largas y utilizar adaptadores.

Estructura Principal

Se definen cuatro botones en el archivo de diseño principal, cada uno redirige a una actividad diferente para demostrar funcionalidades específicas.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rootLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btnDesplegable"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Lista desplegable"/>
    <Button
        android:id="@+id/btnAutocompletar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Autocompletado"/>
    <Button
        android:id="@+id/btnListaMultiple"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Lista con selección"/>
    <Button
        android:id="@+id/btnListaPersonalizada"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Lista detallada"/>
</LinearLayout>

Actividad Principal

La actividad principal implementa un listener para manejar clics en los botones y navegar a las actividades correspondientes.

package com.example.ejemploandroid;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity implements View.OnClickListener {
    private Button botonDesplegable;
    private Button botonAutocompletar;
    private Button botonListaMultiple;
    private Button botonListaPersonalizada;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        botonDesplegable = findViewById(R.id.btnDesplegable);
        botonDesplegable.setOnClickListener(this);
        botonAutocompletar = findViewById(R.id.btnAutocompletar);
        botonAutocompletar.setOnClickListener(this);
        botonListaMultiple = findViewById(R.id.btnListaMultiple);
        botonListaMultiple.setOnClickListener(this);
        botonListaPersonalizada = findViewById(R.id.btnListaPersonalizada);
        botonListaPersonalizada.setOnClickListener(this);
    }

    @Override
    public void onClick(View vista) {
        Intent intentNavegacion = null;
        switch (vista.getId()) {
            case R.id.btnDesplegable:
                intentNavegacion = new Intent(this, DesplegableActivity.class);
                break;
            case R.id.btnAutocompletar:
                intentNavegacion = new Intent(this, AutocompletadoActivity.class);
                break;
            case R.id.btnListaMultiple:
                intentNavegacion = new Intent(this, ListaSeleccionActivity.class);
                break;
            case R.id.btnListaPersonalizada:
                intentNavegacion = new Intent(this, ListaDetalladaActivity.class);
                break;
        }
        if (intentNavegacion != null) {
            startActivity(intentNavegacion);
        }
    }
}

Manejo de Listas Desplegables (Spinner)

Se configuran dos Spinner: uno con datos estáticos de un recurso de cadenas y otro con datos vinculados dinámicamente. Se implementan oyentes para detectar cambios en la selección.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:id="@+id/activityDesplegable"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:text="Elige una ciudad"
        android:textSize="24sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Spinner
        android:id="@+id/spinnerCiudades"
        android:entries="@array/nombresCiudades"
        android:spinnerMode="dialog"
        android:prompt="@string/tituloSeleccion"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:background="@android:color/holo_blue_light"/>
    <TextView
        android:text="Selecciona otra ciudad"
        android:textSize="24sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Spinner
        android:id="@+id/spinnerAlternativo"
        android:spinnerMode="dialog"
        android:prompt="@string/tituloSeleccion"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

En el archivo de recursos de cadenas (strings.xml), se definen las ciudades:

<resources>
    <string name="app_name">EjemploUI</string>
    <string name="tituloSeleccion">Selecciona ciudad</string>
    <array name="nombresCiudades">
        <item>Lima</item>
        <item>Bogotá</item>
        <item>Santiago</item>
        <item>México DF</item>
        <item>Buenos Aires</item>
        <item>Caracas</item>
    </array>
</resources>

La actividad correspondiente escucha eventos y vincula datos dinámicamente.

package com.example.ejemploandroid;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;

public class DesplegableActivity extends Activity {
    private Spinner selectorPrincipal;
    private Spinner selectorDinamico;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_desplegable);
        selectorPrincipal = findViewById(R.id.spinnerCiudades);
        selectorPrincipal.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adaptador, View vista, int posicion, long id) {
                String[] listaCiudades = getResources().getStringArray(R.array.nombresCiudades);
                Toast.makeText(DesplegableActivity.this, "Elegido: " + listaCiudades[posicion], Toast.LENGTH_SHORT).show();
            }
            @Override
            public void onNothingSelected(AdapterView<?> adaptador) {}
        });

        selectorDinamico = findViewById(R.id.spinnerAlternativo);
        String[] nuevasCiudades = {"Quito", "Montevideo", "La Paz", "Asunción"};
        ArrayAdapter adaptadorLocal = new ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, nuevasCiudades);
        selectorDinamico.setAdapter(adaptadorLocal);
    }
}

Autocompletado de Datos

Se utiliza AutoCompleteTextView para sugerir opciones basadas en la entrada del usuario, vinculando un adaptador con datos de ejemplo.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activityAutocompletar"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <AutoCompleteTextView
        android:id="@+id/campoAutocompletar"
        android:completionHint="Escribe para buscar"
        android:completionThreshold="1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

La actividad vincula el adaptador al control.

package com.example.ejemploandroid;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;

public class AutocompletadoActivity extends Activity {
    private AutoCompleteTextView campoEntrada;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_autocompletar);
        campoEntrada = findViewById(R.id.campoAutocompletar);
        String[] sugerencias = {"manzana", "mango", "melocotón", "mandarina", "melón"};
        ArrayAdapter adaptadorSugerencias = new ArrayAdapter(this, android.R.layout.simple_list_item_1, sugerencias);
        campoEntrada.setAdapter(adaptadorSugerencias);
    }
}

Selección Múltiple y Eventos en ListView

Se demuestran ListView con selección múltiple, eventos de clic y pulsación larga, y funcionalidades para seleccionar todos o invertir la selección. Además, se muestran ejemplos de eliminación por pulsación larga.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activityListaSeleccion"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="5dp"
    android:orientation="vertical">
    <ListView
        android:id="@+id/listaEstatica"
        android:entries="@array/nombresCiudades"
        android:divider="@android:color/holo_blue_bright"
        android:dividerHeight="1dp"
        android:listSelector="@android:color/holo_green_light"
        android:choiceMode="multipleChoice"
        android:layout_width="match_parent"
        android:layout_height="200dp"/>
    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:background="@android:color/darker_gray"/>
    <ListView
        android:id="@+id/listaDinamica"
        android:divider="@android:color/holo_blue_bright"
        android:dividerHeight="1dp"
        android:choiceMode="multipleChoice"
        android:listSelector="@android:color/holo_green_light"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:onClick="toggleSeleccion"
            android:text="Invertir selección"
            android:layout_height="wrap_content" />
        <Button
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:onClick="obtenerValores"
            android:text="Obtener valores"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>

La actividad maneja eventos, vincula datos dinámicamente y permite operaciones de selección.

package com.example.ejemploandroid;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class ListaSeleccionActivity extends Activity {
    private ListView vistaListaEstatica;
    private ListView vistaListaDinamica;
    private ArrayAdapter adaptadorLista;
    private List elementosDatos;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lista_seleccion);
        vistaListaEstatica = findViewById(R.id.listaEstatica);
        final String[] datosCiudades = getResources().getStringArray(R.array.nombresCiudades);
        vistaListaEstatica.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adaptador, View vista, int posicion, long id) {
                Toast.makeText(ListaSeleccionActivity.this, datosCiudades[posicion], Toast.LENGTH_SHORT).show();
            }
        });
        vistaListaEstatica.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> adaptador, View vista, int posicion, long id) {
                Toast.makeText(ListaSeleccionActivity.this, "Pulsación larga en: " + datosCiudades[posicion], Toast.LENGTH_SHORT).show();
                return true;
            }
        });

        vistaListaDinamica = findViewById(R.id.listaDinamica);
        elementosDatos = new ArrayList();
        elementosDatos.add("Ana");elementosDatos.add("Luis");
        elementosDatos.add("María");elementosDatos.add("Pedro");
        adaptadorLista = new ArrayAdapter(this, android.R.layout.simple_list_item_multiple_choice, elementosDatos);
        vistaListaDinamica.setAdapter(adaptadorLista);
        vistaListaDinamica.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> adaptador, View vista, int posicion, long id) {
                elementosDatos.remove(posicion);
                adaptadorLista.notifyDataSetChanged();
                return false;
            }
        });
    }

    public void toggleSeleccion(View vista) {
        int totalSeleccionados = vistaListaDinamica.getCheckedItemCount();
        boolean nuevoEstado = totalSeleccionados == 0;
        for (int i = 0; i < vistaListaDinamica.getCount(); i++) {
            vistaListaDinamica.setItemChecked(i, nuevoEstado);
        }
    }

    public void obtenerValores(View vista) {
        StringBuilder acumulador = new StringBuilder();
        for (int i = 0; i < vistaListaDinamica.getCount(); i++) {
            if (vistaListaDinamica.isItemChecked(i)) {
                acumulador.append(vistaListaDinamica.getItemAtPosition(i)).append(", ");
            }
        }
        Toast.makeText(this, acumulador.toString(), Toast.LENGTH_LONG).show();
    }
}

ListView con Contenido Personalizado

Se utiliza SimpleAdapter para mostrar una lista con elementos complejos, como imágenes y texto, vinculando datos desde una colección de mapas.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activityListaDetallada"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ListView
        android:id="@+id/listaUsuarios"
        android:divider="@android:color/holo_purple"
        android:dividerHeight="1dp"
        android:choiceMode="multipleChoice"
        android:listSelector="@android:color/holo_green_light"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

La actividad prepara datos y configura el adaptador.

package com.example.ejemploandroid;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ListaDetalladaActivity extends Activity {
    private ListView vistaLista;
    private SimpleAdapter adaptadorComplejo;
    private List<Map<String, Object>> coleccionDatos;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lista_detallada);
        vistaLista = findViewById(R.id.listaUsuarios);
        String[] claves = {"imagenUsuario", "nombreUsuario", "detalleUsuario"};
        int[] vistas = {R.id.imagenUsuario, R.id.nombreUsuario, R.id.detalleUsuario};
        cargarDatos();
        adaptadorComplejo = new SimpleAdapter(this, coleccionDatos, R.layout.elemento_lista_usuario, claves, vistas);
        vistaLista.setAdapter(adaptadorComplejo);
    }

    private void cargarDatos() {
        coleccionDatos = new ArrayList<Map<String, Object>>();
        Map<String, Object> registro = new HashMap<String, Object>();
        registro.put("imagenUsuario", R.drawable.usuario1);
        registro.put("nombreUsuario", "Carlos");
        registro.put("detalleUsuario", "Desarrollador Android");
        coleccionDatos.add(registro);

        registro = new HashMap<String, Object>();
        registro.put("imagenUsuario", R.drawable.usuario2);
        registro.put("nombreUsuario", "Laura");
        registro.put("detalleUsuario", "Diseñadora UI");
        coleccionDatos.add(registro);

        registro = new HashMap<String, Object>();
        registro.put("imagenUsuario", R.drawable.usuario2);
        registro.put("nombreUsuario", "Roberto");
        registro.put("detalleUsuario", "Gerente de proyectos");
        coleccionDatos.add(registro);
    }
}

El diseño del elemento de lista incluye una imagen, nombre y descripción.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_marginLeft="10dp">
    <ImageView
        android:id="@+id/imagenUsuario"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_gravity="center_vertical"/>
    <LinearLayout
        android:orientation="vertical"
        android:layout_marginLeft="15dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical">
        <TextView
            android:id="@+id/nombreUsuario"
            android:textSize="22sp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/detalleUsuario"
            android:textSize="18sp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>

Etiquetas: Android ui components Spinner AutoCompleteTextView ListView

Publicado el 7-21 07:07