Hoy les moestraré como hacer una animación de fluidos como indicador de carga usando la última versión de Swift 2 y Xcode 7
Abre Xcode 7 y crea un nuevo proyecto elijiendo la plantilla 'Single View Application'. Elije iPhone en dispositivos. Elije Swift como lenguaje principal.
Luego se mostrará una ventana donde configuras propiedades como el "Nombre de Producto", "Lenguaje" (Que por su puesto es Swift), etc
Cuando des click en 'siguiente' se mostrará una ventana de dialogo para guardar el proyecto donde quieras. Donde sea que lo crees, una carpeta se creará con el nombre de la app, y dentro estará el proyecto de Xcode y una carpeta con cada target que tiene tu app (la misma app y una prueba o test en un servidor).
Después de dar click en el botón 'Crear', los archivos para tu proyecyo se generan y Voilá! probablemente estarás mirando el archivo AppDelegate.swift.
Para empezar, lo primero que necesitamos es instalar Cocoapods. Cocoapods corre en Ruby, y es la única dependencia que tiene. Afortunadamente para nosotros, todas las versiones recientes de Mac OS X (desde OS X 10.7) incluyen Ruby en nuestra maquina, así que no hará falta instalarlo. Entonces todo lo que se necesita es actualizar RubyGems (solo para confirmar que estemos en la última versión).
Para hacer lo anterior, abre la Terminal y escribe el siguiente comando: sudo gem update --system
Ingresa tu contraseña cuando se pida. Esta actualización puede tomar un buen tiempo, así que relajense y vayan por un café por unos minutos mientras termina.
Lo siguiente es instalar CocoaPods. Escribe este comando en la Terminal: sudo gem install cocoapods
Por último, ingresa este comando en la Terminal para completar la configuración de CocoaPods pod setup
Este proceso puede tomar también algunos minutos mientras se clona los contenidos de CocoaPods en ~/.cocoapods/ en tu computador. Super, ahora ya tienes configurado CocoaPods!
Abre la Terminal y navega hasta el directorio que contiene el proyecto utilizando el comando 'cd':
cd ~/Ruta/A/la/Carpeta/Conteniendo/FluidLoader
Luego ingresa este comando:
pod init
Esto creará un Podfile por defecto para tu proyecto. Este Podfile será donde se definen nuestras dependencias que necesita el proyecto. Escribe este comando para abrir el Podfile usando Xcode y luego editarlo:
open -a Xcode Podfile
Abrirá el podfile con Xcode y luego tendrás que editar el archivo con lo siguiente:
Aqui cambiamos la platarforma a: ios, ‘9.0’
en la linea 2, pod ‘BAFluidView’
en la linea 8. Después de hacer los cambios, guarda y cierra el podfile.
Tendrás que decirle a CocoaPods que instale las dependencias de tu proyecto. Escribe el siguiente comando en la Terminal (confirma que efectivamente estes en el directorio que contiene el proyecto y el Podfile):
pod install
Verás algo como lo siguiente:
Cierra el proyecto de Xcode (si ya lo has abierto) y Abre el archivo .xworkspace (Adevertencia: De ahora en adelante, como la linea de comandos te mencionó, debes siempre abrir el worspace y no el proyecto!)
Felicitaciones, ya has agregado una dependencia usando CocoaPods. Como el proyecto que hemos importado está escrito en Objective-C necesitamos crear un archivo puente que apunte a los headers de Objetive-C. Crea un archivo Header para tu proyecto y agrega la siguiente linea de código:
#import "BAFluidView.h"
Esta linea importará todas las funciones de BAFluidView
para nuestro proyecto.
También necesitamos importar algunas librerías estandard de los Frameworks de Apple como CoreGraphics, UIKit, Foundation. Ve al proyecto principal en el panel izquierdo baja hasta 'Linked Frameworks and Libraries ' > presiona el botón + y elije los Frameworks que te mencioné.
Ahora configuraremos nuestra storyboard. Esta app descargará una imagen de un servidor y la mostrará en una UIImage. Hasta cuando termine de descargar, lo que haremos será mostrar una linda animación de fluidos. Esta app requiere de un botón para 'empezar' la animación y la descarga. Un 'Label' básico nos ayudará a mostrar el estado de la descarga y una UIImage para mostrar la imágen.
Abre Main.storyboard y verás un solo ViewController que es todo lo que necesitamos.
Ahora tendrás un layout como este en la storyboard:
Conecta el botón de "Empezar", Label de estado de Descarga, UIImageView y las dos UIViews en el archivo ViewController.swift
. Abre el asistente, presiona ctrl + arrastrar y crea todos los outlets uno tras otro. También agrega la acción del botón "Empezar".
Como refencia, mira los nombres de los outlets que utilicé:
(Nota: La UIView que está encima está nombrada como exampleContainerView)
Abre el archivo ViewController.swift y agrega algunas lineas a la función viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
setUpBackground()
startAnime.setTitleColor(UIColor.whiteColor(), forState: .Normal)
titleLabels.text = ""
}
Lo que hacemos es que la funcion setUpBackground asigne una gradiente de color al fondo (background) que hemos ubicado en la storyboard. La siguiente linea cambia el color del botón "Empezar" a blanco. La tercera linea cambia el texto del UILabel a una cadéna de carácteres vacía.
Ahora veamos como luce la funcion setUpBackground:
var gradient = CAGradientLayer()
func setUpBackground() {
if ((self.gradient) != nil) {
self.gradient.removeFromSuperlayer()
self.gradient = nil
}
var tempLayer: CAGradientLayer = CAGradientLayer()
tempLayer.frame = self.view.bounds
tempLayer.colors = [UIColor(netHex: 0x53cf84).CGColor, UIColor(netHex: 0x53cf84).CGColor, UIColor(netHex: 0x2aa581).CGColor, UIColor(netHex: 0x1b9680).CGColor]
tempLayer.locations = [NSNumber(float: 0.0), NSNumber(float: 0.5), NSNumber(float: 0.8), NSNumber(float: 1.0)]
tempLayer.startPoint = CGPointMake(0, 0)
tempLayer.endPoint = CGPointMake(1, 1)
self.gradient = tempLayer
self.backgroundView.layer.insertSublayer(self.gradient, atIndex: 1)
self.exampleContainerView.hidden = true
}
The code above adds a gradient color to the background for good looking UI.
Wait! you’re getting error for the code UIColor(netHex: 0xXXXXXX), don’t you worry about that, I’m using a custom extension to provide the UIColor in Hex format. The extension for it is given below: (Paste this code at the bottom of your ViewController.swift file,i.e, even after the closing brace of your ViewController class)
El código de arriba añade una linda gradiente para mejorar la UI de nuestra app.
Pero espera... te saldrá un error para el código UIColor(netHex: 0xXXXXXX)
, pero no te preocupes, vamos a usar una extension personalizada a UIColor que nos permitirá usar valores en formato hexadecimal. La extension está en el código de abajo:
(Nota: Pega este código al final del archivo ViewController.swift, después de cerrar con "}" la clase)
extension UIColor {
convenience init(red: Int, green: Int, blue: Int) {
assert(red >= 0 && red <= 255, "Invalid red component")
assert(green >= 0 && green <= 255, "Invalid green component")
assert(blue >= 0 && blue <= 255, "Invalid blue component")
self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0)
}
convenience init(netHex:Int) {
self.init(red:(netHex >> 16) & 0xff, green:(netHex >> 8) & 0xff, blue:netHex & 0xff)
}
}
Now we will come to the main function,i.e, the Action of the Start Button that we linked earlier. This function is the most important part in this app. Have a look at it:
Ahora iremos a la función principal, por ejemplo, la Acción del Botón Empezar que enlazamos anteriormente. Esta función es la parte más importante de nuestra app.
Echemos un vistazo:
@IBAction func startAnimation(sender: AnyObject) {
var myView:BAFluidView = BAFluidView(frame: self.view.frame, startElevation: 0.5)
myView.strokeColor = UIColor.whiteColor()
myView.fillColor = UIColor(netHex: 0x2e353d)
myView.keepStationary()
myView.startAnimation()
titleLabels.textColor = UIColor.whiteColor()
self.exampleContainerView.hidden = false
myView.startAnimation()
self.view.insertSubview(myView, aboveSubview: self.backgroundView)
UIView.animateWithDuration(0.5, animations: {
myView.alpha=1.0
}, completion: { _ in
self.titleLabels.text = "Downloading"
self.startAnime.enabled = false
self.exampleContainerView.removeFromSuperview()
self.exampleContainerView = myView
})
if let imageUrl = NSURL(string: "http://swinggolfireland.com/wp-content/uploads/2014/09/OldHead_7PanB.jpg") {
let imageRequest: NSURLRequest = NSURLRequest(URL: imageUrl)
let queue: NSOperationQueue = NSOperationQueue.mainQueue()
NSURLConnection.sendAsynchronousRequest(imageRequest, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
if data != nil {
self.titleLabels.text = "Complete!"
self.exampleContainerView.hidden = true
self.startAnime.enabled = true
println("done")
self.myImage.image = UIImage(data: data)
self.myImage.layer.borderWidth = 2.0
self.myImage.layer.borderColor = UIColor.whiteColor().CGColor
} else {
self.titleLabels.text = "Error Downloading"
self.exampleContainerView.hidden = true
self.startAnime.enabled = true
println("error")
}
})
}
}
El código de arriba será ejecutado una vez el usuario haga tap sobre el botón "Empezar". Trataré de romper el código por partes para que lo entiendas mejor.
var myView:BAFluidView = BAFluidView(frame: self.view.frame, startElevation: 0.5)
myView.strokeColor = UIColor.whiteColor()
myView.fillColor = UIColor(netHex: 0x2e353d)
myView.keepStationary()
myView.startAnimation()
titleLabels.textColor = UIColor.whiteColor()
self.exampleContainerView.hidden = false
myView.startAnimation()
self.view.insertSubview(myView, aboveSubview: self.backgroundView)
UIView.animateWithDuration(0.5, animations: {
myView.alpha=1.0
}, completion: { _ in
self.titleLabels.text = "Downloading"
self.startAnime.enabled = false
self.exampleContainerView.removeFromSuperview()
self.exampleContainerView = myView
})
El código de arriba usa la clase BAFluidView
que habíamos importado a nuestro proyecto usando CocoaPods. Agregamos las propiedades de la animación a myView
que es un objeto BAFluidView
. Luego agregamos propiedades como el color de borde, relleno, etc. y empezamos la animación. Luego usamos UIView.animateWithDuration
y ponemos el exampleContainerView
a myView
. Esto enciende la animación del fluido y la verás en la mitad de la pantalla.
La siguiente parte del código es:
if let imageUrl = NSURL(string: "http://swinggolfireland.com/wp-content/uploads/2014/09/OldHead_7PanB.jpg") {
let imageRequest: NSURLRequest = NSURLRequest(URL: imageUrl)
let queue: NSOperationQueue = NSOperationQueue.mainQueue()
NSURLConnection.sendAsynchronousRequest(imageRequest, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
if data != nil {
self.titleLabels.text = "Complete!"
self.exampleContainerView.hidden = true
self.startAnime.enabled = true
println("done")
self.myImage.image = UIImage(data: data)
self.myImage.layer.borderWidth = 2.0
self.myImage.layer.borderColor = UIColor.whiteColor().CGColor
} else {
self.titleLabels.text = "Error Downloading"
self.exampleContainerView.hidden = true
self.startAnime.enabled = true
println("error")
}
})
El código anterior descarga una imagen de un servidor remoto, durante el tiempo que el archivo se esté descargando, el indicador de carga será una hermosa anición de fluido, que se ocultará al momento de tener la imagen y mostrarse en el UIImage en la app. La descarga de la imagen se hace de manera asíncrona, por ejemplo, ejecutandose en un hilo de fondo evitando bloquear el hilo principal de la app.
¡Listo! Hemos completado exitosamente nuestra app. Eso es todo el tutorial. Si quieres editar la animación puede revisar la documentación de BAFluidView en github, solo juega con el código.
Ahora puedes presionar el botón de Play en Xcode 7 y seleccionar un dispositivo para mostrar la app. Ahora en la última versión de Xcode también puedes ejecutar directamente en tu iPhone sin necesidad de pagar por una cuenta de Apple Developer, así que disfruta de esta animación en tu celular.
Si te gustó este post, y quieres más no olvides seguirme en twitter: @diegosalazarCo y compartir este post. Estaré posteando más tutoriales y noticias sobre Swift y lo útimo en iOS.