1. Code
  2. Mobile Development

Creando Tu Primera Aplicación Con Fuse

Scroll to top

Spanish (Español) translation by RRGG (you can also view the original English article)

Ahora que ha aprendido los conceptos básicos de Fuse, es hora de poner en práctica las cosas y crear una aplicación. En este tutorial, aprenderá cómo desarrollar una aplicación utilizando el marco Fuse. Específicamente, aprenderá lo siguiente:

  • Cómo codificar usando el Margen UX.
  • Cómo utilizar las API de Observación, Temporizador y Geolocalización.
  • Cómo obtener una vista previa de una aplicación usando una vista previa de escritorio y una vista previa personalizada.

Si necesita una actualización sobre Fuse, consulte mi publicación anterior en esta serie: Presentación de Fuse para el desarrollo de aplicaciones multiplataforma.

Pre requisitos

Para comenzar a trabajar con Fuse, vaya a la página de descargas y regístrese para obtener una cuenta. También puede iniciar sesión en una cuenta existente si tiene una.

El fusible está disponible para Windows y MacOS. Descargue e instale el instalador correcto para su plataforma. En la página de descargas, también señalan los complementos de Fuse disponibles para varios editores de texto. Instale uno para su editor de texto. Los complementos de Fuse incluyen la finalización del código, la definición goto y la visualización de los registros generados desde la aplicación, todo lo cual hace que el desarrollo de aplicaciones sea más conveniente.

También explicaremos cómo obtener una vista previa de la aplicación mediante una vista previa personalizada. Esto requiere Android Studio o Xcode para ser instalado en su computadora.

Una comprensión básica de las tecnologías web como HTML, CSS y JavaScript es útil, pero no obligatoria.

Lo Que Crearás

Crearás una aplicación de cronómetro que también mide la distancia recorrida. La distancia se mide mediante geolocalización. El usuario también puede crear vueltas, y la distancia y el tiempo individuales para cada vuelta se mostrarán en la pantalla.

Aquí está cómo se verá la aplicación:

Final Output HIIT StopwatchFinal Output HIIT StopwatchFinal Output HIIT Stopwatch

Puede ver el código fuente completo en el tutorial GitHub repo.

Crear un nuevo proyecto de fusibles

Una vez que haya instalado Fuse Studio, ahora debería poder crear un nuevo proyecto Fuse. Simplemente abra Fuse Studio y haga clic en el botón New Fuse Project. Ingrese el nombre del proyecto y haga clic en Crear:

Create a new Fuse projectCreate a new Fuse projectCreate a new Fuse project

Esto creará una nueva carpeta en el directorio seleccionado. Abra esa carpeta y abra el archivo MainView.ux. Por defecto, solo tendrá el marcado App. Actualízalo para incluir un Texto y luego guarda el archivo:

1
<App>
2
    <Text FontSize="25">Hello World!</Text>
3
</App>

La vista previa ahora debe actualizarse con el texto que especificó:

Hello world outputHello world outputHello world output

Ese es el flujo de trabajo de desarrollo principal en Fuse. Simplemente guarde los cambios en cualquiera de los archivos en el directorio del proyecto, y se reflejarán automáticamente en la vista previa del escritorio.

También puede ver los registros en el panel inferior. Puede activar el suyo utilizando console.log (), como en el navegador. La única diferencia es que debe tener objetos JSON.stringify () para ver su valor, ya que la implementación de console.log () en Fuse solo puede generar cadenas de salida.

UX Markup

Ahora estamos listos para construir la aplicación. Abra el archivo MainView.ux y elimine el elemento de Texto de antes. De esa manera, podemos comenzar con una lista en blanco:

1
<App>
2
3
</App>

Inclyendo Fuentes

Al igual que en un documento HTML, el estándar consiste en incluir los activos (cosas como fuentes, hojas de estilo y scripts) antes del marcado real de la página. Así que agrega lo siguiente App dentro del elemento :

1
<Font File="assets/fonts/roboto/Roboto-Thin.ttf" ux:Global="Thin" />

Esto importa la fuente especificada en el atributo Archivo y le da el nombre Fino. Tenga en cuenta que esto no la convierte en la fuente predeterminada para toda la página. Si desea utilizar esta fuente, debe usar su nombre (Fino) en el texto específico al que desea aplicarlo.

Puede descargar la fuente del tutorial GitHub repo. Después de eso, crea una carpeta assets / fonts / robot dentro del directorio raíz del proyecto y pon el archivo .ttf en ella.

Si desea utilizar otra fuente, puede descargarla desde dafont.com. Ahí es donde descargué la fuente para esta aplicación.

A continuación, queremos usar íconos dentro de la aplicación. Fuse realmente no tiene elementos incorporados ni conjuntos de iconos que le permitan hacer eso. Lo que ofrece es una forma de incluir las fuentes de icono existentes en su aplicación. Como las fuentes de iconos son esencialmente fuentes, podemos usar el mismo método para incluir fuentes:

1
<Font File="assets/fonts/icons/fa-solid-900.ttf" ux:Global="FontAwesome" />

Puede descargar la fuente del icono desde el repositorio GitHub o descargarlo directamente desde fontawesome.com. Tenga en cuenta que no todos los iconos en fontawesome son gratuitos, por lo que es mejor verificar la página del icono real antes de usarlo. Si ve una etiqueta "pro" al lado del icono, entonces no puede simplemente usarla en su proyecto sin pagar.

Incluyendo JavaScript

A continuación, debemos incluir el archivo JavaScript para esta página. Podemos hacer eso usando el elemento :

1
<JavaScript File="scripts/MainView.js"/>

No se olvide de crear los scripts / archivo MainView.js en la raíz del directorio del proyecto.

Creando Nuevos Componentes

Para maximizar la reutilización del código, Fuse nos permite crear componentes personalizados a partir de los existentes. En el siguiente código, estamos usando un Panel  para crear un botón personalizado. Piense en ello como un div que actúa como un contenedor para otros elementos. En este caso, lo estamos usando como un componente reutilizable para crear un botón.

Fuse viene con muchos elementos. Hay elementos para diseñar contenido como , Panel elementos para mostrar controles de usuario, páginas y navegación, secuencias de comandos y datos, y primitivas para construir la interfaz de usuario. Cada uno tiene su propio conjunto de propiedades, que le permite modificar los datos, la presentación y el comportamiento.

Para crear un componente reutilizable, agregue una propiedad ux: Class a un elemento de presentación que le gustaría usar como base. En este caso, estamos usando un Panel  como base. A continuación, puede agregar un estilo predeterminado. Esto es similar a cómo se hace el estilo en CSS. El margen agrega espacio fuera del contenedor. Aquí solo hemos especificado un valor único, por lo que este margen se aplica en todos los lados del panel. El color agrega un color de fondo al elemento:

1
<Panel ux:Class="ToggleBtn" Margin="4" Color="#007bff">
2
    
3
</Panel>

Dentro del Panel, queremos mostrar el texto del botón. Queremos que esto se convierta en un componente reutilizable, por lo que necesitamos una forma de pasar las propiedades para cuando usemos este componente más adelante. Esto nos permite lograr resultados diferentes solo cambiando las propiedades.

Dentro del Panel , use el tipo de datos del valor que desea pasar como el nombre del elemento y luego agregue el nombre de la propiedad usando ux: Propiedad. A continuación, puede mostrar el valor proporcionado a la propiedad utilizando {ReadProperty PropertyName}, donde PropertyName es el valor que ha proporcionado a ux: Property. Esto le permitirá suministrar un Texto de propiedad siempre que esté utilizando el componente TogglBtn .

1
<string ux:Property="Text" />
2
<Text Value="{ReadProperty Text}" Color="#fff" FontSize="18" Alignment="Center" Margin="20,15" />

A continuación, queremos ofrecer al usuario algún tipo de comentario mientras se presiona el botón. Podemos hacer eso a través de desencadenantes y animadores. Los desencadenantes son básicamente los oyentes del evento; en este caso WhilePressed, . Y los animadores son las animaciones o efectos que desea realizar mientras el activador está activo. El siguiente código hará que el botón sea 10% más grande que su tamaño original y cambie su color. Duración y DurationBack le permiten especificar cuánto tiempo le lleva a la animación alcanzar su punto máximo y alcanzar su fin.

1
<WhilePressed>
2
    <Scale Factor="1.1" />
3
    <Change this.Color="#636363" Duration="0.03" DurationBack=".03" />
4
</WhilePressed>

A continuación, creamos el componente IconBtn . Como su nombre indica, este es un botón que solo muestra un icono como su contenido. Esto funciona de la misma manera que el componente anterior, aunque hay algunas cosas nuevas que hemos hecho aquí.

Primero está la propiedad ux: Name. Esto nos permite dar un nombre a un elemento específico para que podamos consultarlo más adelante. En este caso, lo estamos usando para cambiar su propiedad Color mientras se presiona el botón.

También usamos un elemento condicional llamado WhileTrue . Esto nos permite desactivar el disparador WhilePressed cuando el valor de is_running es falso. Le proporcionaremos el valor de esta variable una vez que lleguemos a la parte de JavaScript. Por ahora, sepa que esta variable indica si el temporizador se está ejecutando actualmente o no.

1
<Panel ux:Class="IconBtn">
2
    <string ux:Property="Text" />
3
    <Text Font="FontAwesome" Color="#333" ux:Name="LapText" FontSize="40" Alignment="Center">{ReadProperty Text}</Text>
4
    <WhileTrue Value="{is_running}"> 
5
        <WhilePressed>
6
            <Change LapText.Color="#ccc" Duration="0.09" /> <!-- change text color -->
7
            <Rotate Degrees="90" Duration="0.02"/> <!-- rotate the button by 90 degrees -->
8
        </WhilePressed>
9
    </WhileTrue>
10
</Panel>

Contenido Principal

Ahora podemos continuar con el contenido principal. Primero, envolvemos todo en un StackPanel . Como su nombre indica, esto nos permite "apilar" sus hijos vertical u horizontalmente. De forma predeterminada, usa orientación vertical, por lo que no es necesario que lo especifique explícitamente:

1
<StackPanel  Margin="0,25,0,0" Padding="20">    
2
    
3
</StackPanel>

En el código anterior, utilizamos cuatro valores para el margen. A diferencia de CSS, la distribución del valor es izquierda, arriba, derecha, abajo. Si solo se especifican dos valores, es de izquierda a derecha, arriba-abajo. Puede usar la herramienta de selección en Fuse Studio para visualizar los márgenes aplicados.

A continuación, agregamos una imagen de fondo para la página. Esto acepta la ruta del archivo a la imagen de fondo que desea usar. Un StretchMode of Fill hace que el fondo se estire para llenar toda la pantalla:

1
<ImageFill File="assets/images/seigaiha.png" StretchMode="Fill" />

Puede descargar la imagen de fondo que he usado del tutorial GitHub repo. O puede encontrar patrones similares en el sitio web de Toptal.

A continuación, muestre el nombre de la aplicación. Debajo está el campo de texto de tiempo transcurrido. Este texto debe actualizarse con frecuencia, por lo que debemos convertirlo en una variable que se puede actualizar a través de JavaScript. Para generar un texto inicializado en el archivo JavaScript de esta página, debe ajustar el nombre de la variable entre llaves. Más adelante, verá cómo el valor de esta variable proviene del archivo JavaScript:

1
<Text Value="HIIT Stopwatch" Color="#333" FontSize="18" Alignment="Center" Margin="0,0,0,10" />
2
<Text FontSize="65" Font="Thin" TextAlignment="Center" Margin="0,0,0,20">{time_elapsed}</Text>

A continuación, usamos el componente IconBtn que creamos anteriormente, similar a un entorno web en el que usamos el ID de la fuente. En Fuse, debe usar el Unicode asignado a la fuente del icono que desea usar. También necesita usar & # x como prefijo. Cuando se presiona este botón (llamado Clicked), se ejecuta la función addLap () declarada en el archivo JavaScript:

1
<IconBtn Text="&#xf2f1;" Clicked="{addLap}" />

En Font Awesome, puede encontrar el unicode de la fuente del icono en su propia página.

Justo debajo del botón para agregar una nueva vuelta hay texto que indica que el botón de arriba es para agregar nuevas vueltas:

1
<Text Value="Lap" Color="#333" FontSize="15" Alignment="Center" Margin="0,5,0,20" />

A continuación, muestre el botón para iniciar y detener el temporizador. Esto también ejecuta una función que declararemos más tarde:

1
<ToggleBtn Text="{toggle_btn_text}"  Clicked="{toggle}" />

A continuación, tenemos que imprimir las vueltas agregadas por el usuario. Esto incluye el número de vuelta, la distancia recorrida y el tiempo dedicado. El elemento Each nos permite iterar a través de una colección de objetos y mostrar las propiedades individuales para cada objeto:

1
<StackPanel Margin="20,40">
2
    <Each Items="{laps}">
3
        <DockPanel Margin="0,0,0,15">
4
            <Text Alignment="Left" FontSize="18" Color="#333" Value="{title}" />
5
            <Text Alignment="Center" FontSize="18" Color="#333" Value="{distance}" />
6
            <Text Alignment="Right" FontSize="18" Color="#333" Value="{time}" />
7
        </DockPanel>
8
    </Each>
9
</StackPanel>

En el código anterior, estamos usando el DockPanel para envolver los contenidos de cada artículo. Este tipo de panel nos permite "atracar" a sus hijos en diferentes lados (arriba, izquierda, derecha e inferior) del espacio disponible. Por defecto, esto coloca a sus hijos directamente uno encima del otro. Para espaciarlos uniformemente, debe agregar la propiedad Alineación.

Código JavaScript

Ahora estamos listos para agregar el código JavaScript. En Fuse, JavaScript se usa principalmente para la lógica empresarial y para trabajar con la funcionalidad nativa del dispositivo. Los efectos, las transiciones y las animaciones para interactuar con la interfaz de usuario ya se manejan con el marcado UX.

Comience importando todas las API que necesitamos. Esto incluye Observable, que se usa principalmente para asignar variables en la UI. Estas variables se pueden actualizar utilizando JavaScript. Timer es el equivalente de las funciones setTimeout y setInterval en la versión web de JavaScript. GeoLocation nos permite obtener la ubicación actual del usuario:

1
var Observable = require("FuseJS/Observable");
2
var Timer = require("FuseJS/Timer");
3
var GeoLocation = require("FuseJS/GeoLocation");

A continuación, inicializamos todos los valores observables que usaremos. Estas son las variables que ha visto anteriormente en el marcado UX. Los valores de estas variables se actualizan a lo largo de la vida útil de la aplicación, por lo que los convertimos en una variable observable. Esto nos permite actualizar los contenidos de la interfaz de usuario cada vez que cambia alguno de estos valores:

1
var time_elapsed = Observable(); // the timer text

2
var toggle_btn_text = Observable(); // the text for the button for starting and stopping the timer

3
var is_running = Observable(); // whether the timer is currently running or not

4
var laps = Observable(); // the laps added by the user

Después de eso, ahora podemos establecer los valores iniciales para el botón de alternar y el texto del temporizador:

1
toggle_btn_text.value = 'Start'; // toggle button default text

2
time_elapsed.value = "00:00:00"; // timer default text

Así es como cambias el valor de una variable observable. Dado que estos no están dentro de ninguna función, esto debería actualizar la interfaz de usuario inmediatamente cuando se inicia la aplicación.

Establezca los valores iniciales para el temporizador, el tiempo de vuelta y la ubicación para cada vuelta:

1
var time = 0; // timer

2
var lap_time = 0; // time for each lap

3
var locations = []; // location of the user for each lap

La función de alternancia toggle() se utiliza para iniciar y detener el temporizador. Cuando el temporizador se detiene actualmente y el usuario toca el botón de alternar, es la única vez que reiniciamos los valores para el temporizador y las vueltas. Esto se debe a que queremos que el usuario vea estos valores incluso después de detener el temporizador.

Después de eso, obtenga la ubicación actual del usuario y presiónela en la matriz de ubicaciones. Esto nos permite compararlo con la próxima ubicación más adelante, una vez que el usuario agregue una vuelta. Luego, crea un temporizador que se ejecuta cada 10 milisegundos. Incrementamos tanto el tiempo total como el lap_time para cada ejecución. Luego actualice la UI con el valor formateado utilizando la función formatTimer ():

1
function toggle(){
2
3
    if(toggle_btn_text.value == 'Start'){ // the timer is currently stopped (alternatively, use is_running)

4
        laps.clear(); // observable values has a clear() method for resetting its value

5
        time_elapsed.value = formatTimer(time);
6
        is_running.value = true;
7
8
        locations.push(GeoLocation.location); // get initial location

9
10
        timer_id = Timer.create(function() {
11
            time += 1; // incremented every 10 milliseconds

12
            lap_time += 1; // current lap time

13
            
14
            time_elapsed.value = formatTimer(time); // update the UI with the formatted time elapsed string

15
        }, 10, true);
16
    }else{
17
        // next: add code for when the user stops the timer

18
    }
19
20
    toggle_btn_text.value = (toggle_btn_text.value == 'Start') ? 'Stop' : 'Start';
21
}

Cuando el usuario detiene el temporizador, lo eliminamos utilizando el método delete () en el temporizador. Esto requiere el timer_id que se devolvió cuando se creó el temporizador:

1
Timer.delete(timer_id); // delete the running timer

2
// reset the rest of the values

3
time = 0;
4
lap_time = 0;
5
is_running.value = false; 

A continuación está la función para formatear el temporizador. Esto funciona convirtiendo los milisegundos en segundos y en minutos. Ya sabemos que esta función se ejecuta cada 10 milisegundos. Y el tiempo se incrementa en 1 cada vez que se ejecuta. Entonces, para obtener los milisegundos, simplemente multiplicamos el tiempo por 10. A partir de ahí, calculamos los segundos y minutos en función del valor equivalente para cada unidad de medida:

1
function formatTimer(time) {
2
    function pad(d) {
3
        return (d < 10) ? '0' + d.toString() : d.toString();
4
    }
5
6
    var millis = time * 10;
7
    var seconds = millis / 1000;
8
9
    mins = Math.floor(seconds / 60);
10
    secs = Math.floor(seconds) % 60,
11
    hundredths = Math.floor((millis % 1000) / 10);
12
    return pad(mins) + ":" + pad(secs) + ":" + pad(hundredths);
13
}

Cada vez que el usuario toca el botón Actualizar, se ejecuta la función addLap (). Esto agrega una nueva entrada en la parte superior de las vueltas observables:

1
function addLap() {
2
    if(time > 0){ // only execute when the timer is running

3
4
        lap_time_value = formatTimer(lap_time); // format the current lap time

5
        lap_time = 0; // reset the lap time

6
7
        var start_loc = locations[laps.length]; // get the previous location

8
        var end_loc = GeoLocation.location; // get the current location

9
        locations.push(end_loc); // add the current location

10
11
        var distance = getDistanceFromLatLonInMeters(start_loc.latitude, start_loc.longitude, end_loc.latitude, end_loc.longitude); 
12
        
13
        // add the new item on top

14
        laps.insertAt(0, {
15
            title: ("Lap " + (laps.length + 1)),
16
            time: lap_time_value,
17
            distance: distance.toString() + " m."
18
        });
19
        
20
    }
21
}

Aquí está la función para obtener la distancia cubierta en metros. Esto usa la fórmula Haversine:

1
function getDistanceFromLatLonInMeters(lat1, lon1, lat2, lon2) {
2
    function deg2rad(deg) {
3
      return deg * (Math.PI/180)
4
    }
5
6
    var R = 6371; // radius of the earth in km

7
    var dLat = deg2rad(lat2 - lat1);  
8
    var dLon = deg2rad(lon2 - lon1); 
9
    var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
10
        Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); 
11
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 
12
    var d = (R * c) * 1000; // Distance in m

13
    return d;
14
}

No te olvides de exportar todos los valores observables:

1
module.exports = {
2
    toggle: toggle,
3
    toggle_btn_text: toggle_btn_text,
4
    is_running: is_running,
5
    time_elapsed: time_elapsed,
6
    laps: laps,
7
    addLap: addLap
8
}

Paquete de Geolocación

Para mantener las cosas ligeras, Fuse realmente no incluye todos los paquetes que admite de forma predeterminada. Para cosas como la geolocalización y las notificaciones locales, debes decirle a Fuse que las incluya cuando construyas la aplicación. Abra StopWatch.unoproj en la raíz del directorio de su proyecto e incluya Fuse.GeoLocation en la matriz de Paquetes:

1
"Packages": [
2
    "Fuse",
3
    "FuseJS",
4
    "Fuse.GeoLocation" // add this
5
],

Esto debería indicarle a Fuse que incluya el paquete de geolocalización cada vez que construya la aplicación para obtener una vista previa personalizada o para generar un instalador.

Configuración para vista previa personalizada

Antes de poder ejecutar la aplicación en su dispositivo iOS, primero debe agregar un identificador de paquete a la aplicación. Abra el archivo StopWatch.unoproj y agregue lo siguiente en iOS. Esta será la identificación única de la aplicación cuando se envíe a la tienda de aplicaciones:

1
"Packages": [
2
    // ...
3
],
4
"iOS": {
5
    "BundleIdentifier": "com.yourname.stopwatch",
6
    "PreviewBundleIdentifier": "com.yourname.stopwatch.preview"
7
}

Luego, en Xcode, inicie sesión con su cuenta de desarrollador de Apple. Si aún no tiene uno, puede ir al sitio web para desarrolladores de Apple y crear uno. De hecho, es libre de desarrollar y probar aplicaciones en su dispositivo iOS. Sin embargo, existen algunas limitaciones si no eres parte del programa de desarrollo.

Una vez que haya creado su cuenta, vaya a las preferencias de Xcode y agregue su cuenta de Apple. A continuación, haga clic en Administrar certificados y agregue un nuevo certificado para el desarrollo de iOS. Este certificado se utiliza para garantizar que la aplicación proviene de una fuente conocida.

Una vez hecho esto, ahora debería poder ejecutar la aplicación en su dispositivo. Haga clic en Vista previa> Vista previa en iOS en Fuse Studio y espere a que se inicie Xcode. Una vez que Xcode esté abierto, selecciona tu dispositivo y haz clic en el botón de reproducción. Esto construirá la aplicación e instalará en su dispositivo. Si hay un error de compilación, lo más probable es que el identificador del paquete de vista previa no sea único:

change the bundle IDchange the bundle IDchange the bundle ID

Cambiar el identificador de paquete a algo único debería resolver el problema. Una vez que el error en la sección de firma desaparece, haga clic en el botón de reproducción nuevamente para reconstruir la aplicación. Esto debería instalar la aplicación en tu dispositivo.

Sin embargo, no serás capaz de abrir la aplicación hasta que la apruebes. Puede hacerlo en su dispositivo iOS yendo a Configuración> General> Administración de dispositivos y seleccionando el correo electrónico asociado con su cuenta de Desarrollador de Apple. Apriételo, y eso debería desbloquear la aplicación.

Para Android, deberías ser capaz de pre visualizar la aplicación sin pasos adicionales.

Conclusión

¡Eso es! En este tutorial, aprendió los conceptos básicos de la creación de una aplicación utilizando el marco Fuse. Específicamente, has creado una aplicación de cronómetro. Al crear esta aplicación, ha aprendido a trabajar con el marcado UX de Fuse y algunas de las API de JavaScript de Fuse. También aprendió a usar Fuse Studio para previsualizar la aplicación en su computadora y su teléfono mientras la desarrolla.