Ejemplo de menú con botones que despliegan subopciones. Este menú sustituye al APPWIZARD, de forma que podamos personalizar a nuestro gusto los menús de la aplicación.

Vista del menú en Android Vista del menú desplegado
Vista de los frames de la demo

NOTA: Se ha desarrollado en un teléfono (800*480) con orientación vertical, simplemente como ejemplo de desarrollo.

Descarga Ejemplo

1.- Login automático

Lo primero que llama la atención es que la aplicación NO pide usuario y contraseña para entrar en la aplicación, esto se puede conseguir teniendo un usuario “admin” sin contraseña en la tabla de usuarios de la Base de Datos, además, en el mappings, dentro del nodo APP, hemos de especificar el atributo autologon=“true”.

<app prefix="gen" version="0.0.0.1" autologon="true" entry-point="menus" resolution-width="480" resolution-height="800">

2.- Sustituir APPWIZARD

Para sustituir al APPWIZARD, tendremos que definir una colección en el fichero mappings.xml, con el diseño de menú que queremos mostrar. En el nodo APP, hemos de especificar en el atributo entry-point=“NOMBRE_COLECCION_MENUS”, el nombre de la colección donde hemos definido el menú.

3.- Resolución de las imágenes

A la hora de diseñar nuestros menús, hemos de tener en cuenta los distintos dispositivos y resoluciones que tenemos hoy en día en el mercado. Para ello, tomamos como base un dispositivo para hacer nuestro diseño, en el ejemplo hemos tomado un dispositivo con una resolución de 800×480 píxeles.

Toda nuestra aplicación la realizaremos para ésta resolución y en el nodo APP especificaremos los atributos resolution-width=“480” y resolution-height=“800”. Estos atributos nos permiten que nuestra aplicación se reescale automáticamente si utilizamos otro dispositivo con diferente resolución, de forma que el framework se encarga automáticamente del reescalado.

Utilizar preferentemente dispositivos con una resolución alta (1920×1080, full hd) para desarrollar la aplicación, pues hacer que las imágenes grandes se reescalen a una resolución más pequeña no supone ningún problema, sin embargo, cuando unas imágenes pequeñas haya que reescalarlas para verlas en un dispositivo con mayor resolución, provocará que las imágenes se vean pixeladas.

4.- Código de la colección menús


Código Explicación
special=“true” Este atributo, a nivel de nodo COLL, nos permite que NO se ejecute ninguna SQL contra la Base de Datos para obtener los valores de la colección.
notab=“true” Este atributo, a nivel de nodo COLL, nos permite que NO se muestren las posibles pestañas(group) que pudiese haber.
bgcolor=“#00FFFFFF” Los dos primeros dígitos del color nos especifican la OPACIDAD, en este caso 00, con lo cual es transparente y no se muestra el color.
MAP_SUBOPCION Este campo Numérico que tenemos invisible, lo utilizaremos como campo bandera para que sepamos que submenú hemos de mostrar, en principio vale 0 y NO se muestra ningúna subopción.
scroll=“true” Utilizado en el frame1, para que si hay muchas opciones/subopciones, se haga scroll. Se ha puesto únicamente en este frame, para que el resto siga apareciendo en pantalla sin que se vean afectados por el scroll.
Subopciones1/2 Este frame lo hemos utilizado para englobar las subopciones y poder así mostrarlas u ocultarlas todas a la vez. Tiene especificado el atributo disablevisible=“MAP_SUBOPCION&lt;&gt;1” que especifica la condición para que se oculten las subopciones, en este caso las subopciones permanecerán invisibles MIENTRAS MAP_SUBOPCION sea distinto de 1. Los caracteres &lt; y &gt; hemos de codificarlos así puesto que al estar dentro de un XML, no podemos poner los símbolos de < y > para que no crea que estamos cerrando o abriendo un nodo XML.
NOTA: Este frame lo hemos utilizado por comodidad y a modo de ejemplo, intentar evitar en la medida de lo posible el uso de frames, puesto que una mayor complejidad de la estructura visual de la aplicación implicará un mayor tiempo de “repintado”, cada vez que algún campo cambie y provoque un refresco de la pantalla.
method=“executenode(toggleMENU(1))“ Utilizado en los botones de las opciones principales, llamamos al nodo “toggleMENU” y le pasamos como parámetro la opción en la que hemos pulsado.
show-wait-dialog=“false” Utilizado en el nodo “toggleMENU”, para que no muestre el mensaje “CARGANDO…” mientras está ejecutándose el script que hayamos definido.
method=“executenode(abrirCOLL('Clientes'))“ Utilizado en los botones de las subopciones, llamamos al nodo “abrirCOLL” y le pasamos como parámetro la colección que queremos abrir.
appData.userinterface.openmenu coll,26,1 Utilizado en el nodo “abrirCOLL” para abrir una colección, los atributos son “colección”, máscara(permisos) y modo (0-listado, 1-edición). Ver más información de los valores de la máscara Aquí
<coll name="menus" title="menus" notab="true" special="true" filter="" sort="">
    <group name="General" id="1"> 
 
    <frame name="frmFondo" width="480" height="800" imgbk=".\icons\FondoEntry.jpg">
 
        <frame name="frmtitle" framebox="false" width="480" align="center" height="80" bgcolor="#00FFFFFF">
            <prop name="MAP_TITLE" type="TL" align="center" labelbox="false" title="By XOne - Menú sin Appwizard " visible="1" width="480" height="50" labelwidth="20" forecolor="#FFFFFFFF" />
            <prop name="MAP_SUBOPCION" type="N" visible="0" />
        </frame>
 
        <frame name="Frame1" width="480" height="720" labelbox="false" scroll="true">
 
            <prop name="MAP_BT_OPCION1" type="B" method="executenode(toggleMENU(1))" class="opcion_appwizard" title="Opción 1" />
 
                <frame name="Subopciones1" width="480" height="250" labelbox="false" disablevisible="MAP_SUBOPCION&lt;&gt;1">
                    <prop name="MAP_BT_OPCION1_1" type="B" method="executenode(abrirCOLL('Clientes'))" class="subopcion_appwizard" title="SubOpción 1.1" />
                    <prop name="MAP_BT_OPCION1_2" type="B" method="executenode(abrirCOLL('Clientes'))" class="subopcion_appwizard" title="SubOpción 1.2" />
                    <prop name="MAP_BT_OPCION1_3" type="B" method="executenode(abrirCOLL('Clientes'))" class="subopcion_appwizard" title="SubOpción 1.3" />
                </frame>
 
            <prop name="MAP_BT_OPCION2" type="B" method="executenode(toggleMENU(2))" class="opcion_appwizard" title="Opción 2" />
 
                <frame name="Subopciones2" width="480" height="250" labelbox="false" disablevisible="MAP_SUBOPCION&lt;&gt;2">
                    <prop name="MAP_BT_OPCION2_1" type="B" method="executenode(abrirCOLL('Clientes'))" class="subopcion_appwizard" title="SubOpción 2.1" />
                    <prop name="MAP_BT_OPCION2_2" type="B" method="executenode(abrirCOLL('Clientes'))" class="subopcion_appwizard" title="SubOpción 2.2" />
                    <prop name="MAP_BT_OPCION2_3" type="B" method="executenode(abrirCOLL('Clientes'))" class="subopcion_appwizard" title="SubOpción 2.3" />
                </frame>
 
            <prop name="MAP_BT_OPCION3" type="B" title="Opción 3" class="opcion_appwizard" />
            <prop name="MAP_BT_OPCION4" type="B" title="Opción 4" class="opcion_appwizard" />
            <prop name="MAP_BT_OPCION5" type="B" title="Opción 5" class="opcion_appwizard" />
        </frame>
    </frame>
    </group>
 
    <toggleMENU show-wait-dialog="false">
        <action name="runscript">
            <param name="subopcion" />
            <script language="VBScript">
                'Pasamos como parámetro la opcion principal en que ha pinchado.
                'Preguntamos y si le ha vuelto a dar a la que estaba desplegada, la colapsamos.
                if this("MAP_SUBOPCION")=subopcion then
                    this("MAP_SUBOPCION")=0
                else
                    this("MAP_SUBOPCION")=subopcion
                end if
            </script>
        </action>
    </toggleMENU>
 
    <abrirCOLL>
        <action name="runscript">
            <param name="coll" />
            <script language="VBScript">
                'Para abrir una colección "nombre_coll",mascara,modo(0-listado, 1-edicion)
                appData.userinterface.openmenu coll,26,1
            </script>
        </action>
    </abrirCOLL>
</coll>