Supongamos que quiero construir una aplicación llamada "Memora". Cuando uso la plantilla de Xcode para SwiftUI puedo ver que se genera un proyecto con la siguiente estructura:
Memora
| - Memora
| | - MemoraApp.swift
| | - ContentView.swift
| | - Assets.xcassets
| | - Info.plist
| | - Preview Content
| | | - Preview Assets.xcassets
MemoraApp hace las veces de AppDelegate donde se va a configurar e inicializar la aplicación. Se puede ver que tiene una etiqueta @main que señala el punto de partida de la aplicación. Por otro lado, la estructura MemoraApp conforma el protocolo App que, aparte de tener un body de tipo some Scene, que sirve para gestionar las varias escenas de la pantalla, genera la función static main para arrancar la aplicación.
import SwiftUI
//
@main
struct MemoraApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Por otro lado tenemos a ContentView que es una estructura que conforma a View, que debe tener un body de tipo some View.
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
}
}
Escena (Scene)
Scene es un protocolo que maneja la interfaz de la aplicación y la adapta a cada plataforma. Aunque se puede crear una escena manualmente conformando el protocolo Scene, existen varias escenas por defecto para cada sistema. Por ejemplo, WindowGroup, Window, DocumentGroup, Settings y MenuBarExtra.
WindowGroup puede manejar múltiples ventanas para iPhone, iPad y MacOS, y crea un Scene con una ventana. Las ventanas determinan el espacio donde se pueden pintar los gráficos, pero no generan ningún contenido visible.
Vista (View)
La interfaz de usuario se construye con contenedores llamados Views. Las vistas están organizadas en una jerarquía, una dentro de otra.
View es un protocolo que requiere implementar una variable computada body que retorna una vista (some View).
Cuando el sistema procesa una estructura View, crea un "root-view", determinando su tamaño a partir del de su contenedor (sea una ventana u otra vista). Por esta razón, ContentView es asignado como el "root view" de la ventada de WindowGroup, y su tamaño vendrá dado por el tamaño de la ventana.
Las vistas definidas en la propiedad body funcionan diferente: Toman el tamaño del contenedor y se lo proponen a su contenido. Luego, el contenido decide qué tamaño tomar.
Previsualización
En la parte inferior del archivo aparece un ContentView_Previews de tipo PreviewProvider, que fue sustituido en versiones recientes de Xcode con el macro "freestanding" llamado #Preview. Este produce la previsualización del lado derecho de la pantalla que debe ser usada para mostrar varios casos de uso de la pantalla en cuestión que no debe ser muy compleja. En caso de que no cargue la previsualización (diría "Preview paused"), hacer clic en el botón de reanudar.
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#Preview {
ContentView()
}
-
Preview(_:traits:body:): Produce la previsualización de una vista en el canvas. El primer argumento es una etiqueta para la previsualización (porque puede haber varias). El segundo configura la previsualización por medio de una estructura con propiedades de configuración como la orientación, tamaño de la vista, etc. El argumentobodyrecibe el closure con la vista que se va a pintar.
En caso de querer previsualizar el contenido en una ventana que se ajuste al tamaño intrínseco del contenido, hay que usar el "trait" .sizeThatFitsLayout (disponible desde iOS 17) si se usa #Preview o .previewLayout(.sizeThatFits) en la estructura que conforma PreviewProvider (que no está disponible dentro de #Preview).
// Usando #Preview
#Preview(traits: .sizeThatFitsLayout) {
// Solo disponible desde iOS 17
ZStack {
Color.element
Text("Hola mundo")
.padding()
}
.frame(width: 300, height: 100)
}
// Usando PreviewProvider
struct Example_Previews: PreviewProvider {
static var previews: some View {
// Solo disponible desde iOS 17
ZStack {
Color.element
Text("Hola mundo")
.padding()
}
.frame(width: 300, height: 100)
.previewLayout(.sizeThatFits)
}
}
En caso de que se ponga un punto de quiebre en el código, este solo servirá al ejecutar la aplicación en un simulador. El modo de previsualización, desde Xcode 13, no ejecuta el código en modo Depuración (Debug) por lo que es imposible depurarla.
Configuración de la previsualización
- En la esquina inferior izquierda del canvas hay una opción llamada "Device settings" que permite configurar, de forma gráfica, aspectos como
.preferredColorScheme(.dark)o la orientación de interfaz preferida (e.g.landscapeLeft). Esta opción aparece deshabilitada cuando la previsualización se construye conformando el protocoloPreviewProvider. - En la parte inferior del área de trabajo, cerca del botón azul para habilitar/deshabilitar los puntos de interrupción, está el botón "Environment Overrides" que permite cambiar algunos valores sobre el simulador, similares al "Device settings" anterior. Se puede encontrar una lista de las variables de ambiente del dispositivo aquí.
- En la parte inferior del canvas, al lado derecho del botón "Device Settings", aparece un botón que permite elegir el dispositivo en el que se quiere previsualizar la vista. Si se usa
PreviewProviderse puede poner el modificador.previewDevice()que recibe unPreviewDevice(rawValue: "…"), que a su vez recibe por parámetro el nombre del dispositivo que se quiere usar. Este último modificador es ignorado cuando se usa#Preview. - A una previsualización se le puede cambiar el título. Si se usa
#Preview, basta con ponerlo dentro de los paréntesis. Si se usaPreviewProviderse puede poner con.previewDisplayName().
Canvas / Lienzo
- El botón "Selectable" de la parte inferior del preview permite hacer clic sobre un componente visual para resaltarlo, cambiando el color de su borde a azul.
- El botón "Live" de la parte inferior del preview permite interactuar con la aplicación como si estuviera ejecutándose en un simulador.
- En la esquina superior izquierda del canvas hay un botón que permite anclar cierta previsualización a la pantalla, lo que permite hacer cambios en otro archivo sin tener que ir y volver para ver como afecta a la vista anclada.
- Hacer
Command + Shift + Lpara abrir la biblioteca de componentes. Allí tendremos varias categorías: Views, Modifiers, Snippets, Media. Para mantener la biblioteca de componentes abierta hacerCommand + Option + Shift + L. - Para recargar la previsualización usar
Option + Command + P.
Algunas características modo "Selectable"
Para lo siguiente se asume que el canvas está en modo "Selectable":
- Al hacer
Option + clicken un componente visual, se resalta el código en la vista asociada que lo construye. - Al hacer
Command + click(oControl + Command + click) en un componente visual, se despliega un menú encima con varias opciones, entre ellas: "Embed". Al hacer clic en esta, se agrega una plantilla que envuelve al componente visual en un contenedor. NOTA: Solo se puede envolver un componente.
Targets
La configuración de una aplicación se almacena en un "target". El "target" incluye cosas como el nombre y versión de la aplicación, los sistemas que soporta y las cualidades de la aplicación, como el acceso a la cámara o a los servicios de iCloud, orientaciones permitidas del dispositivo y la versión de despliegue (versiones soportadas del sistema operativo, por la aplicación).
Info
La lista con los valores de configuración de un "target" específico se encuentra en la pestaña "Info". Estos valores están almacenados dentro de un archivo de extensión .plist. Para agregar más información, hay que hacer clic derecho, seguido de "add row". Aquí se encuentra información configurada en otras pestañas como nombre de la aplicación y versión del sistema operativo mínima soportada.
Bibliografía
- Kodeco Team; Bello, A.; Morefield, B.; Reichelt, S.; & Tam, A. (2023). SwiftUI by Tutorials (Fifth Edition): Declarative App Development on the Apple Ecosystem. Kodeco Incorporated.
Top comments (0)