El menú contextual flotante en Android es un menú que muestra una lista de opciones asociadas al contexto de un view, al cual el usuario le hizo un click prolongado:
¿Cómo se comporta?
Las acciones mostradas en el menú se ajustan al contexto del ítem que está involucrado, por lo que solo es posible seleccionar una de ellas para aplicar. Adicional puedes especificar un título para su cabecera («Food Space.jpg» en la imagen anterior).
¿Qué elementos del framework uso?
El menú contextual flotante es representado por la clase ContextMenu
en el framework de Android. Conviene subrayar que este componente necesitará de:
- Un recurso de menú
- A
ContexMenu.ContextMenuInfo
para proveeer información al crear el menú - A
MenuInflater.inflate()
para inflar el menú - A
registerForContextMenu()
para registrar el view - A
onCreateContextMenu()
para crear el menú - A
onContextItemSelected()
para responder a los eventos de las opciones
No te preocupes, la idea de los siguientes apartados es explicar cómo encadenar los anteriores elementos.
Ejemplo De Menú Contextual Flotante En Android
En este tutorial aprenderás a asociar el disparo de una acción contextual a un view, crear y mostrar el menú que cubre dicha acción; y procesar los eventos sobre cada opción.
Asimismo crearás una App de ejemplo que despliega un menú contextual flotante cuando se hace click y se sostiene un ImageView
:
Puedes descargar el proyecto Android Studio desde el siguiente enlace por si necesitas corroborar el código en más detalle:
Con esto claro, adentrémonos a la receta para crear el menú.
1. Crear Recurso De Menú
En primer lugar, crea el archivo XML con la definición de la estructura del menú que deseas mostrar.
Por tanto añade tres elementos para recrear las acciones de: Descargar, Compatir y Copiar descripción; sobre el menú flotante que usamos en la App de ejemplo:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/download"
android:title="@string/download" />
<item
android:id="@+id/share"
android:title="@string/share" />
<item
android:id="@+id/copy"
android:title="@string/copy_description" />
</menu>
Ten en cuenta que los ítems de menú de la clase ContextMenu
no soportan atajos ni iconos, por lo que los valores que asignes en atributos como android:icon
y android:numericShorcut
perderán efecto.
2. Asociar View Con ContextMenu
Luego debes registrar el view que actuará como origen de la aparición del menú contextual flotante. Dicho registro lo logras con el método registerForContextMenu()
desde tu actividad pasando la instancia del view:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val image: ImageView = findViewById(R.id.image)
registerForContextMenu(image)
}
}
En concreto pasamos al ImageView
que tenemos en el layout de la actividad a partir de una plantilla Empty Activity en Android Studio:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:padding="16dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:layout_width="match_parent"
android:layout_height="250dp"
android:id="@+id/image"
android:src="@drawable/image"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:contentDescription="@string/image_content_description" />
</androidx.constraintlayout.widget.ConstraintLayout>
3. Crear ContextMenu
Al igual que con el menú de opciones, las actividades y fragmentos poseen un método de enganche para inflar el menú contextual flotante llamado onCreateContextMenu()
:
override fun onCreateContextMenu(
menu: ContextMenu,
v: View,
menuInfo: ContextMenu.ContextMenuInfo?
) {
super.onCreateContextMenu(menu, v, menuInfo)
menuInflater.inflate(R.menu.context_menu, menu)
menu.setHeaderTitle(R.string.image_content_description)
}
Este método es llamado por el sistema cuando se notifica un click prolongado sobre el view registrado. Y como ves, recibe los siguientes tres parámetros:
menu
: ElMenuContext
que está siendo construidov
: El view para el cual se está construyendo el menú flotantemenuInfo
: Información extra acerca del view relacionado al menú
Debido a que tienes un recurso de menú construido, simplemente invocas a inflate()
pasando a menu
para inflar la definición sobre el objeto.
En cuanto al título de la cabecera, invoca a setHeaderTitle()
desde el menú y pasa el recurso string o CharSequence
que será mostrado.
Añadir Items Programáticamente
Por otra parte, si lo que quieres es crear el menú programáticamente, entonces usa el método add()
para agregar ítems a la instancia en construcción del menú:
override fun onCreateContextMenu(
menu: ContextMenu,
v: View,
menuInfo: ContextMenu.ContextMenuInfo?
) {
super.onCreateContextMenu(menu, v, menuInfo)
menu.setHeaderTitle(R.string.image_content_description)
menu.add(R.string.download)
menu.add(R.string.share)
menu.add(R.string.copy_description)
}
El anterior código producirá el mismo resultado visual que nuestro recurso XML.
4. Responder A Selección De Ítems
El siguiente paso es sobrescribir al método onContextItemSelected()
con el fin de procesar la selección de ítems del menú contextual flotante.
Su funcionamiento es similar a onOptionsItemSelected()
, recibe como argumento la instancia MenuItem
seleccionada por el usuario:
override fun onContextItemSelected(item: MenuItem): Boolean {
Toast.makeText(this, item.title, Toast.LENGTH_SHORT).show()
return when (item.itemId) {
R.id.download -> {
download()
true
}
R.id.share -> {
share()
true
}
R.id.copy -> {
copy()
true
}
else -> super.onContextItemSelected(item)
}
}
Puesto que tenemos varios ítems del menú a procesar usamos la expresión when
para realizar las comparaciones de los IDs existentes con el estado de itemId
del ítem clickeado.
Por consiguiente, cada caso manejado correctamente retornará true
, de lo contrario retornamos la implementación del padre.
Añadir Escucha Programáticamente
También puedes omitir el uso de onOptionsItemSelected()
si añades observadores del tipo OnMenuItemListener
sobre las instancias MenuItem
producidas por add()
:
override fun onCreateContextMenu(
menu: ContextMenu,
v: View,
menuInfo: ContextMenu.ContextMenuInfo?
) {
super.onCreateContextMenu(menu, v, menuInfo)
menuInflater.inflate(R.menu.context_menu, menu)
menu.setHeaderTitle(R.string.image_content_description)
menu.add("Cambiar nombre").setOnMenuItemClickListener { item ->
showMessage(item.title)
true
}
}
La escucha tiene un solo controlador (onMenuItemClick()
), por lo que es posible convertir la clase anónima en una lambda.
5. Responder A Cierre Del Menú
Para terminar, procesaremos el cierre del menú contextual flotante con la sobrescritura del método onContextMenuClosed()
de la actividad. Concretamente mostraremos un Toast
evidenciando la ocurrencia de este evento:
Como resultado tendremos una sencilla línea de creación al interior de onContextMenuClosed()
:
override fun onContextMenuClosed(menu: Menu) {
showMessage("Menú cerrado")
}
¿Qué Sigue?
En este tutorial aprendiste a crear menús contextuales flotantes para permitir al usuario ejecutar acciones relacionadas con un view específico. Ahora puede ir a estudiar el menú contextual producido por el Action Mode cuando se interactúa con una lista de ítems.
Más Contenidos Android
Únete Al Discord De Develou
Si tienes problemas con el código de este tutorial, preguntas, recomendaciones o solo deseas discutir sobre desarrollo Android conmigo y otros desarrolladores, únete a la comunidad de Discord de Develou y siéntete libre de participar como gustes. ¡Te espero!