Necesitaba hacer un menú contextual para Android, pero no quería que fuese un AlertDialog. Con éste, al hacerse un difuminado (blurring) del fondo, se le otorga una importancia excesiva al menú. Por eso, como todos hacemos, me puse a buscar.
Existe una solución bastante sencilla para esto, el PopupMenu. Me costó bastante encontrarlo, cuando es un tipo de widget bastante común (recuerdo haber utilizado uno equivalente con XAML). Su uso es muy sencillo. El problema viene cuando queremos poblarlo de forma dinámica. Nuestra primera idea será usar un Adapter. Pero no lo soporta, por lo que estamos en principio abocados a poblarlo mediante un xml.
Como con esto no solucionaba mi problemática, buscando (ya sabéis dónde) encontré varias soluciones. La que más me gustó fue crear una vista propia la cual heredase de un Spinner. Pero la cosa se complica bastante. Mucho para lo simple que es lo que queremos conseguir.
Así que le di vueltas al argumento y pensé en coger un menú, crearlo desde cero, y añadirle ítems. Esto tiene en principio dos problemas:
Android no permite crear un Menu.
Hacer que dicho menú aparezca justo en el lugar deseado.
Buscando otra vez, encontré un hilo en el que, como tanta otras veces, la respuesta aceptada no era la buena, o no al menos la que más me convencía. Ésta en cambio, por lo sencilla y encaminada que nos deja, es genial.
val popupMenu = PopupMenu(activity, p0.customView)
val menu = popupmenu.menu
menu.add("casa")
menu.add("coco")
// Hay que arreglar esto, sacar fuera para evitar creación excesiva de objetos.
popupmenu.setOnMenuItemClickListener { item ->
context.toast("Item clickado: ${item.title}")
true
}
popupmenu.show()
Básicamente lo que hacemos es crear el Popup Menu, coger el Menu que éste nos crea, y trabajar sobre él. Así solucionamos el tema de la creación y el de la posición, puesto que el segundo argumento que se le pasa al constructor es la vista a la cuál queremos anclar dicho Popup Menu.
Es bastante problemático (por ahora no lo he conseguido) cambiarle el estilo al Popup Menu. Sí que es importante tener claro que el contexto que se le pasa es fundamental. Primero le estaba pasando como contexto el TabLayout (en el gif se ve a qué me refiero). Pero para éste defino el siguiente estilo:
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
Esto hace que el menú salga oscuro y chirríe mucho con el resto de la aplicación. Por eso le paso la Activity, lo que me permite obtener un estilo claro del menú.
El framework de Android nos da otro constructor para Popup Menu. Lo probé de la siguiente forma:
val popupMenu = PopupMenu(context, p0.customView, Gravity.CENTER, 0, R.style.PopupMenu)
Y aunque el estilo cambia, se sobreescriben algunos atributos que no puedo recuperar (por ejemplo la elevación, tan obsesivamente comentada y adorada por Google y los fanáticos de Material Design).