En este tutorial, aprenderemos cómo planificar aplicaciones de IU usando Ver y aprenderemos cómo usar
variables de Estado para modificar las IU.
Tiempo estimado de lectura: 25 minutos.
SwiftUI nos permite olvidarnos por completo de Interface Builder (IB) y los guiones gráficos. IB y Xcode eran aplicaciones separadas antes de Xcode 4, pero el "acoplamiento" entre ellos todavía es visible cuando editamos el nombre IBAction o IBOutlet y nuestra aplicación falla, por lo que IB no sabe nada acerca de los cambios en el código. O cuando establecemos identificadores para segues o para celdas de tabla, pero Xcode no puede verificarlos, ya que son cadenas.
SwiftUI al rescate! Inmediatamente vemos los cambios en la Vista tan pronto como ingresamos el código. Los cambios en un lado dan como resultado una actualización en el otro, por lo que siempre están relacionados. No hay identificadores de cadena que puedan estar equivocados. Y este es todo el código, pero es mucho más pequeño que si lo escribiéramos usando UIKit, por lo que es más fácil de entender, editar y depurar. Dime, ¿no es maravilloso?
Vamos
Comencemos un nuevo proyecto en el proyecto Xcode (
Shift-Command-N ), seleccione
iOS App Aplicación de vista única , llame a RGBullsEye y asegúrese de elegir
SwiftUI como interfaz.
Ahora
AppDelegate.swift se divide en dos archivos:
AppDelegate.swift y SceneDelegate.swift , y SceneDelegate contiene una ventana:
SceneDelegate casi no está relacionado con SwiftUI, con la excepción de esta línea:
window.rootViewController = UIHostingController(rootView: ContentView())
UIHostingController crea un controlador de vista para SwiftUI-view
ContentView .
Nota: UIHostingController nos permite integrar SwiftUI-view en una aplicación existente. Agregue el controlador de vista de alojamiento a nuestro guión gráfico y cree una secuencia desde el controlador UIView. Luego usamos Control-drag con segue en el código del controlador de vista para crear una IBSegueAction , donde configuramos el controlador de alojamiento en rootView - SwiftUI-view.
Cuando se inicia la aplicación, la ventana muestra una instancia de
ContentView , que se define en el archivo
ContentView.swift . Esta es una
estructura que se ajusta al protocolo
View :
struct ContentView: View { var body: some View { Text("Hello World") } }
Esta es una declaración de SwiftUI del contenido de un ContentView (
cuerpo ). Ahora hay una vista de texto con el texto Hello World.
Justo debajo de ContentView_Previews devuelve una instancia de ContentView.
struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
Aquí podemos establecer los datos de prueba para la vista previa. Pero, ¿dónde está exactamente esta vista previa?
Inmediatamente después del código hay un gran espacio vacío con esto arriba:

Haz clic en
Reanudar , espera un momento y ...

Dibuja nuestra interfaz de usuario
Algo familiar no es visible: este es el archivo
Main.storyboard . Vamos a crear nuestra interfaz de usuario usando SwiftUI, justo en el código, en el proceso de ver la vista previa: ¿qué obtenemos allí? Pero no se preocupe, no tenemos que escribir cientos de líneas de código para crear nuestras vistas.
SwiftUI es declarativo: usted establece cómo debería ser su IU y SwiftUI convierte todo esto en un código eficiente que hace todo el trabajo. Apple le permite crear tantas vistas como sea necesario para que el código sea simple y directo. Se recomiendan especialmente las vistas reutilizables con parámetros; esto es similar a asignar código a una función separada. Lo harás tú mismo más tarde.
Nuestra aplicación tendrá muchas vistas, por lo que, para empezar, esbozaremos las vistas de texto como apéndices.
Reemplazar texto ("Hola mundo") con esto:
Text("Target Color Block")
Si es necesario, haga clic en
Reanudar para actualizar la vista previa.
Ahora haga
Comando-Clic en esta vista en la
vista previa y seleccione
Incrustar en HStack :

Tenga en cuenta que su código también ha cambiado:
HStack { Text("Target Color Block") }
Copie y pegue el operador de texto y edítelo dentro de nuestra HStack. Tenga en cuenta: no separamos los operadores con una coma, sino que escribimos cada uno de ellos en una nueva línea:
HStack { Text("Target Color Block") Text("Guess Color Block") }
Y así se ve en la vista previa:

Ahora preparemos un lugar para los
resguardos deslizantes colocando
HStack en
VStack . Esta vez haremos
Command-Click en HStack
en nuestro código :

Elija
Incrustar en VStack ; aparecerá un nuevo código, pero la vista previa no cambiará. Un poco más tarde agregaremos la vista debajo de los bloques de color futuros.
Agregue una nueva línea inmediatamente después de HStack, haga clic en
+ en la barra de herramientas para abrir la biblioteca y arrastre
Vertical Stack a una nueva línea:

Como se esperaba, tanto el código como la vista previa han cambiado:

Termine el trabajo en el borrador de la interfaz de usuario, para que todo se vea así:
VStack { HStack { Text("Target Color Block") Text("Guess Color Block") } Text("Hit me button") VStack { Text("Red slider") Text("Green slider") Text("Blue slider") } }
En el nuevo VStack, aparecerán tres controles deslizantes un poco más tarde, así como un botón entre los controles deslizantes y los bloques de color.
Seguimos trabajando en la interfaz de usuario
Ahora practiquemos en SwiftUI para completar una HStack que contiene bloques de colores:
HStack {
Cada bloque de color tiene un rectángulo. El bloque de color de destino (Target) tiene una vista de Texto debajo del rectángulo, y el seleccionado (Guess) tiene tres vistas de Texto. Un poco más tarde, reemplazaremos 'xxx' con los valores reales de los controles deslizantes.
Usando las variables '@State'
En SwiftUI, podemos usar variables regulares, pero si queremos que el cambio de la variable afecte a la IU, entonces marcamos variables como
'@State' . En nuestra aplicación, seleccionamos el color, de modo que todas las variables que afectan el color seleccionado son variables '@State'.
Agregue estas líneas dentro de la
estructura ContentView , antes de la declaración del
cuerpo :
let rTarget = Double.random(in: 0..<1) let gTarget = Double.random(in: 0..<1) let bTarget = Double.random(in: 0..<1) @State var rGuess: Double @State var gGuess: Double @State var bGuess: Double
Los valores de R, G y B se encuentran entre 0 y 1. Inicializamos los valores deseados con valores aleatorios. También podríamos inicializar los valores seleccionados a 0.5, pero dejarlos sin inicializar por ahora para mostrar lo que se debe hacer en este caso.
Vayamos un poco más abajo a la
estructura ContentView_Previews , que inicializa la instancia de ContentView
para la vista previa . Ahora el inicializador necesita los valores iniciales de los valores seleccionados. Cambie
ContentView () así:
ContentView(rGuess: 0.5, gGuess: 0.5, bGuess: 0.5)
Cuando hacemos los controles deslizantes, en la vista previa sus valores estarán en el medio.
También debemos arreglar el
inicializador en
SceneDelegate , en la función de
escena (_: willConnectTo: opciones :) - reemplace
ContentView () con lo siguiente:
window.rootViewController = UIHostingController(rootView: ContentView(rGuess: 0.5, gGuess: 0.5, bGuess: 0.5))
Cuando se carga la aplicación, los punteros del control deslizante estarán en el centro.
Ahora agregue un modificador de color al rectángulo de destino:
Rectangle() .foregroundColor(Color(red: rTarget, green: gTarget, blue: bTarget, opacity: 1.0))
El modificador
.foregroundColor crea una nueva vista Rectángulo con el color especificado por valores RGB generados aleatoriamente.
Del mismo modo, modifique el rectángulo de conjetura:
Rectangle() .foregroundColor(Color(red: rGuess, green: gGuess, blue: bGuess, opacity: 1.0))
Con valores de R, G y B en 0.5 obtenemos un color gris.
Haz clic en Reanudar y espera un momento.

Hacer que la vista sea reutilizable
Primero, no pensaremos en reutilizar y simplemente crearemos un control deslizante para rojo. En
VStack para controles deslizantes, reemplace el conector de Texto ("
Control deslizante rojo") con este
HStack :
HStack { Text("0") .foregroundColor(.red) Slider(value: $rGuess) Text("255") .foregroundColor(.red) }
Hicimos el color del texto en la vista de texto rojo. Y agregaron Slider con un valor predeterminado. El rango predeterminado del control deslizante es de 0 a 1, esto es algo que nos conviene perfectamente.
Nota: Sabemos que el control deslizante va de 0 a 1, y la etiqueta de texto es '255' para la comodidad de los usuarios que están acostumbrados a representar valores RGB en el rango de 0 a 255.
¿Pero cuál es el icono
$ para la variable? ¿Sabemos acerca de
? y! cuando se trabaja con
opcionales , y ahora también
$ ?
A pesar de que es tan pequeño y discreto, es muy importante.
RGuess en sí mismo es solo un valor de solo
lectura . Pero
$ rGuess es un enlace , lo necesitamos para actualizar el rectángulo del color seleccionado cuando el usuario mueve el control deslizante.
Para comprender la diferencia, establezca los valores para la Vista de tres textos debajo del rectángulo predecible:
HStack { Text("R: \(Int(rGuess * 255.0))") Text("G: \(Int(gGuess * 255.0))") Text("B: \(Int(bGuess * 255.0))") }
Aquí solo usamos los valores, no los cambiamos, por lo que no necesitamos el prefijo $.
Espere la actualización de vista previa:

Los rectángulos de colores se contrajeron ligeramente para ajustarse al control deslizante. Pero las etiquetas de texto del control deslizante se ven desordenadas: están demasiado presionadas en los bordes. Agreguemos otro modificador a HStack - relleno:
HStack { Text("0") .foregroundColor(.red) Slider(value: $rGuess) Text("255") .foregroundColor(.red) } .padding()
Ahora mucho mejor!

Haga
Command-Click en el control deslizante rojo HStack y seleccione
Extraer subvista :

Esto funciona igual que
Refactor ▸ Extract to Function , pero para la vista SwiftUI.
En este punto, aparecerán varios mensajes de error, no se preocupe, ahora lo solucionaremos.
Asigne un nombre a la vista resultante
ColorSlider y agregue este código en la parte superior, frente al cuerpo de nuestra nueva vista:
@Binding var value: Double var textColor: Color
Ahora reemplace
$ rGuess con $ value y .red con textColor :
Text("0") .foregroundColor(textColor) Slider(value: $value) Text("255") .foregroundColor(textColor)
Volvamos a la definición de ColorSlider () en VStack y agreguemos nuestros parámetros:
ColorSlider(value: $rGuess, textColor: .red)
Asegúrese de que la vista previa esté bien con el control deslizante rojo y reemplace los apéndices de texto con los controles deslizantes verde y azul. No olvide insertar los parámetros correctos allí:
ColorSlider(value: $gGuess, textColor: .green) ColorSlider(value: $bGuess, textColor: .blue)
Haga clic en
Reanudar para actualizar la vista previa:

Nota: es posible que haya notado que a menudo tiene que hacer clic en Reanudar . Si te gustan los atajos, probablemente te encantará Option-Command-P .
Y ahora algo bueno! En la esquina inferior derecha de la vista previa, haga clic en el botón de
vista previa en vivo :

¡La vista previa en vivo nos permite interactuar con la vista previa como si la aplicación se estuviera ejecutando en un simulador!
Intenta mover los controles deslizantes:

Genial Pasamos a la etapa final. Después de todo, queremos saber qué tan bien elegimos el color.
Mostrar alerta
Después de configurar los controles deslizantes en las posiciones deseadas, el usuario presiona el botón
Hit Me , después de lo cual aparece
Alerta con una calificación.
Primero, agregue un método a ContentView para calcular la puntuación. Entre las variables @State y
cuerpo agregue este método:
func computeScore() -> Int { let rDiff = rGuess - rTarget let gDiff = gGuess - gTarget let bDiff = bGuess - bTarget let diff = sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff) return Int((1.0 - diff) * 100.0 + 0.5) }
El valor de
diferencia es simplemente la distancia entre dos puntos en el espacio tridimensional, es decir, el valor del error del usuario. Para obtener una estimación, reste diff de 1 y luego reduzca su valor al rango de 0 a 100. Cuanto menor sea la diferencia, mayor será la estimación.
Luego reemplace el trozo de
Texto ("Hit me button") con este código:
Button(action: { }) { Text("Hit Me!") }
El botón tiene acción y etiqueta, como UIButton. Queremos que la acción active una vista de alerta. Pero, si creamos Alerta en el botón de acción, no pasará nada.
En su lugar, haremos que Alert forme parte de ContentView y agregaremos una variable '@State' de tipo Bool. Luego establecemos esta variable en verdadero, en el lugar donde queremos que aparezca nuestra alerta en el botón de acción. El valor se restablecerá a falso, para ocultar la alerta, cuando el usuario oculte la alerta.
Agregue esta variable '@State':
@State var showAlert = false
Luego agregue este código como un botón de acción:
self.showAlert = true
self es necesario para nosotros, ya que showAlert está dentro del cierre.
Finalmente, agregue el modificador de alerta al botón, para que nuestro botón se vea completamente así:
Button(action: { self.showAlert = true }) { Text("Hit Me!") } .alert(isPresented: $showAlert) { Alert(title: Text("Your Score"), message: Text("\(computeScore())")) }
Pasamos $ showAlert como un enlace, ya que el valor de esta variable cambiará en el momento en que el usuario oculte la alerta, y este cambio hará que la vista se actualice.
SwiftUI tiene un inicializador simple para la vista de alerta. Tiene un botón Aceptar de forma predeterminada, por lo que ni siquiera necesitamos configurarlo como parámetro.
Active la vista previa en vivo, mueva los controles deslizantes y presione el botón Hit me. Voila!

Ahora con la vista previa en vivo, ya no necesita un simulador de iOS. Aunque con él puedes probar tu aplicación horizontalmente:

Conclusión
Aquí puede descargar el borrador de publicación terminado.
Este tutorial solo ha cubierto un poco a SwiftUI, pero ahora tiene una impresión de las nuevas características de Xcode para crear UI y vistas previas, así como cómo usar las variables '@State' para actualizar su UI.
Por simplicidad, no creamos un modelo de datos para RGB. Pero la mayoría de las aplicaciones crean modelos de sus datos utilizando estructuras o clases. Si desea realizar un seguimiento de los cambios en el modelo en SwiftUI, debe cumplir con el protocolo
ObservableObject e implementar la propiedad
willChange , que le notifica los cambios.
Consulte los ejemplos de Apple y especialmente el
flujo de datos a través de SwiftUI .
Para que SwiftUI sea más fácil de entender, puede agregar una vista SwiftUI a una aplicación existente. Vea ejemplos de cómo hacer esto rápida y fácilmente.
Vea
mi publicación sobre la implementación de listas plegables / desplegables usando SwiftUI.
Finalmente, estudie la
documentación para SwiftUI , ¡y realmente hay muchas
cosas útiles!