Entre para a LISTA VIP da Black Friday

00

DIAS

00

HORAS

00

MIN

00

SEG

Clique para saber mais
Alura > Cursos de Mobile > Cursos de iOS > Conteúdos de iOS > Primeiras aulas do curso iOS: construindo uma lista de tarefas com MVC com View Code

iOS: construindo uma lista de tarefas com MVC com View Code

Camada view do MVC - Apresentação

Olá! Eu sou a Giovanna Moeller, instrutora na Alura, e quero te desejar boas-vindas a mais um curso de iOS, agora com foco na arquitetura MVC.

Audiodescrição: Giovanna se descreve como uma mulher branca de cabelos loiros lisos e longos, sobrancelhas loiras, e olhos castanho-escuros. Ela veste uma camisa azul com o nome Alura em branco, e está sentada nos estúdios da Alura, com uma parede clara ao fundo iluminada em gradiente roxo e azul-escuro, e uma estante preta à esquerda da instrutora, com enfeites e pontos de iluminação amarela.

O que vamos aprender?

Durante este curso, vamos trabalhar em um projeto chamado Tasky, um aplicativo de lista de tarefas onde podemos, por exemplo, adicionar uma nova tarefa. Para exemplificar, vamos criar uma nova tarefa com o título "Estudar Swift" e a descrição "MVC", finalizando no botão "Salvar" abaixo.

Uma vez criadas as tarefas, podemos marcá-las como completas ou desmarcá-las. Além disso, conseguimos remover tarefas. Ao longo do processo, todas essas tarefas são armazenadas para evitar perder qualquer dado quando fecharmos o aplicativo e o abrirmos novamente.

Ao longo do curso, trabalharemos com a arquitetura MVC:

É muito importante aprender sobre essa arquitetura, pois é a arquitetura padrão utilizada pela Apple em seus aplicativos iOS quando estudamos sobre o framework UIkit.

Durante este projeto, também utilizaremos View Code, da abordagem programática. Sendo assim, não iremos utilizar o Storyboard, afinal, é isso que o mercado de trabalho pede.

Conclusão

Para realizar este curso, é importante ter conhecimentos prévios sobre a linguagem Swift e a construção de interfaces utilizando View Code. Não se preocupe, pois temos todos esses conteúdos aqui na plataforma da Alura!

Te aguardamos para a primeira aula!

Camada view do MVC - Configurando o nosso projeto

Vamos iniciar nosso projeto?

Configurando o projeto

Primeiramente, vamos acessar o Figma do projeto Tasky, cujo link ficará disponível para consulta.

Analisando o projeto no Figma

Começaremos pela tela inicial, composta por duas imagens:

Além disso, há um texto e um botão "Vamos começar!" logo abaixo.

Ilustração de uma tela de aplicativo chamado Tasky, mostrando uma figura estilizada de uma pessoa sentada em degraus de papel, com um laptop no colo. A pessoa tem cabelo preto e veste uma blusa amarela, calças azuis e tênis roxos. Há elementos gráficos abstratos, como pontos e formas ao redor da figura. Logo acima, o logotipo da Tasky formado por um ícone roxo de lista de tarefas com o nome 'Tasky' em preto à direita. O fundo é um degradê de azul para púrpura. Na parte inferior, um texto em preto diz: 'Prepare-se para conquistar o dia, uma lista de cada vez.' Abaixo, um botão preto com o texto 'Vamos começar!' em branco. No topo da imagem aparecem a hora '9:41' em preto à esquerda e ícones de sinal de operadora de celular, Wi-Fi e bateria à direita.

Removendo o arquivo Main.storyboard

Agora vamos acessar o Xcode, onde já criamos o projeto, mas nada além disso. Para criá-lo, usamos o Storyboard, pois trabalhamos com o framework UIkit.

No entanto, como vamos utilizar o View Code, que é uma abordagem programática, não utilizaremos o Storyboard. Portanto, precisamos remover o arquivo Main do Storyboard. Após clicar no arquivo Main com o botão direito, basta selecionar a opção "Delete" e, em seguida, "Move to Trash".

Removendo as referências do arquivo Main

Após remover o arquivo, precisamos remover todas as suas referências. Para começar, vamos acessar a pasta do aplicativo e abrir a aba "Info". Nela, encontraremos uma tabela com a chave "Main storyboard file base name" definida como Main. Vamos apagar essa linha teclando "Delete".

Na sequência, vamos abrir o arquivo Info, localizado na pasta do projeto TaskyApp. Neste arquivo, temos o "Application Scene Manifest". Clicaremos na seta à esquerda para expandir.

Continuaremos expandindo os itens "Scene Configuration", "Window Application Session Role", e "Item 0 (Default Configuration)", até encontrarmos o "Storyboard Name", que está definido como Main. Apagaremos essa linha da mesma forma que fizemos anteriormente.

Com isso, removemos todas as referências do Storyboard.

Renomeando a classe ViewController

Agora precisamos configurar o arquivo SceneDelegate.swift, para que a classe ViewController seja a ViewController inicial. Dessa forma, quando a pessoa usuária abrir o aplicativo, essa será a primeira ViewController visualizada.

Começaremos renomeando a classe no arquivo ViewController.swift de ViewController para HomeViewController para ficar mais significativo.

Primeiro vamos clicar sobre o arquivo ViewController.swift no menu lateral esquerdo e renomeá-lo para HomeViewController.swift. Feito isso, podemos renomear a classe na linha 10 do código.

HomeViewController.swift:

// código omitido

import UIKit

class HomeViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

}

Configurando o arquivo SceneDelegate.swift

Feito isso, podemos voltar ao arquivo SceneDelegate.swift e modificar o método scene() da linha 15, realizando todos os ajustes necessários para utilizar o View Code.

Na linha 19, em vez de definir a variável _, definiremos uma variável chamada windowScene. Logo após essa linha, passaremos self.window e instanciaremos um objeto do tipo UIWindow(), passando o windowScene como parâmetro.

SceneDelegate.swift:

// código omitido

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
    guard let windowScene = (scene as? UIWindowScene) else { return }
    self.window = UIWindow(windowScene: windowScene)
}

// código omitido

Também precisamos dizer que self.window?.rootViewController, que é a ViewController inicial, será igual a UINavigationController(), onde selecionaremos a segunda opção com o rootViewController, pois iremos utilizar navegação neste aplicativo.

Nesse caso, a rootViewController será definida como HomeViewController(). Após instanciar a ViewController, por último, precisamos fazer um self.window?.makeKeyAndVisible().

// código omitido

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
    guard let windowScene = (scene as? UIWindowScene) else { return }
    self.window = UIWindow(windowScene: windowScene)
    self.window?.rootViewController = UINavigationController(rootViewController: HomeViewController())
    self.window?.makeKeyAndVisible()
}

// código omitido

Assim, configuramos o aplicativo para utilizar o View Code. A última coisa que falta para terminar essa configuração inicial é importar as imagens e as cores.

Importando imagens

De volta ao Figma, temos três imagens ao longo de todas as telas: o logotipo da Tasky; a imagem principal da tela inicial; e outra imagem secundária que aparece na tela de tarefas. Além disso, existem algumas cores que precisamos coletar os respectivos códigos para utilizá-las.

Com o Xcode aberto, vamos acessar o arquivo Assets, onde importaremos as imagens. Após baixar todas no formato SVG (home-illustration.svg, logo.svg, e tasks-illustration.svg), basta arrastá-las da pasta para o arquivo Assets.

Como utilizamos o formato SVG, abriremos o menu lateral no ícone retangular do canto superior direito. No campo "Resizing" da seção "Image Set", marcaremos a caixa de seleção "Preserve Vector Data".

Feito isso, no campo "Scales", vamos alterar da opção "None" para "Single Scale" no menu suspenso. Como usamos SVG, ele não perde a qualidade, então é um ótimo formato de imagem para utilizar.

Importando cores

Também adicionaremos cores. Para isso, após clicar com o botão direito do mouse dentro do arquivo Assets, vamos selecionar "New Color Set".

A primeira cor será chamada de DarkPurple, que será um roxo mais escuro. Feito isso, vamos ajustar o campo "Appearances" na seção "Color Set" à direita. Em vez de "Any, Dark", mudaremos para "None". Dessa forma, teremos apenas uma cor.

No campo Input Method, na seção "Color" mais abaixo, vamos alterar de "8-bit (0-255)" para "8-bit Hexadecimal". Por fim, o código hexadecimal dessa primeira cor será #22183B.

Agora que temos o tom de roxo escuro configurado, vamos criar outra cor. Com o botão direito, selecionamos "New Color Set" novamente, mas essa cor será um lilás, então chamaremos de Lilac.

Da mesma forma, definiremos o campo "Appearances" como "None" em vez de "Any, Dark". O código hexadecimal agora é #5F5CFF. Com isso, temos um tom de lilás mais escuro e azulado.

Criando o arquivo Constants.swift

Agora que importamos as imagens e as cores necessárias, para finalizar, criaremos um novo arquivo. Para começar, dentro da pasta do projeto TaskyApp, criaremos uma nova pasta chamada "Utils". Nessa nova pasta, criaremos um arquivo do tipo "Swift File" chamado Constants.swift.

Constants.swift:

// código omitido

import Foundation

No escopo deste arquivo, criaremos um enum para armazenar os valores das imagens e das cores que acabamos de importar no arquivo Assets. Dessa forma, não utilizaremos como valores mágicos.

Na linha 10, definiremos um enum chamado AssetsConstants. Entre chaves, começaremos referenciando: criaremos uma variável estática (static let) chamada homeIllustration na linha 11.

Essa variável será igual ao nome exato da imagem que colocamos no arquivo Assets, ou seja, home-illustration entre aspas duplas.

// código omitido

import Foundation

enum AssetsConstants {
    static let homeIllustration = "home-illustration"
}

Na linha abaixo, faremos o mesmo com static let tasksIllustration, que será igual a tasks-illustration entre aspas duplas. Para o logotipo, vamos declarar uma static let chamada logo.

Por fim, para as cores, vamos declarar uma static let chamada darkPurple na linha 14, que será igual a DarkPurple; e uma static let chamada lilac, que será igual a Lilac.

// código omitido

import Foundation

enum AssetsConstants {
    static let homeIllustration = "home-illustration"
    static let tasksIllustration = "tasks-illustration"
    static let logo = "logo"
    static let darkPurple = "DarkPurple"
    static let lilac = "Lilac"
}

Esse processo é somente para centralizar tudo o que importamos e evitar escrever em string toda vez que formos utilizar essas imagens e cores na nossa aplicação. Afinal, às vezes podemos cometer algum tipo de erro, então consideramos isso uma boa prática.

Ajustando o arquivo HomeViewController.swift

Para recapitular e verificar se está em funcionamento, voltaremos ao arquivo HomeViewController.swift. No escopo da função viewDidLoad(), apagaremos o comentário da linha 14.

No lugar disso, escreveremos view.backgroundColor para aplicar uma cor de fundo, que será igual a UIColor() recebendo o parâmetro named. Nesse caso, em vez de passarmos DarkPurple em formato de string, vamos chamar AssetsConstants.darkPurple.

HomeViewController.swift:

// código omitido

import UIKit

class HomeViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor(named: AssetsConstants.darkPurple)
    }

}

Com o comando "Command + R", podemos executar o aplicativo. Normalmente, ele demora um pouco na primeira execução, mas ao final, teremos o aplicativo exibindo a tela inicial com a cor de fundo roxa.

Conclusão

Agora que já configuramos todo o projeto no Xcode, começaremos a construir a tela inicial. Nos encontramos no próximo vídeo!

Camada view do MVC - Construindo a tela inicial: gradiente e imagens

Neste vídeo, começaremos a construir a tela inicial e adicionaremos os primeiros elementos necessários.

Construindo a tela inicial: gradiente e imagens

Analisando o projeto no Figma

Observando o projeto Tasky no Figma, percebemos que a tela inicial é composta por um fundo gradiente, que vai do branco até o lilás que importamos no arquivo Assets. Dito isso, vamos voltar ao Xcode.

Criando uma extensão da ViewController

Poderíamos adicionar esse código diretamente na classe HomeViewController, mas haveria um problema: se quiséssemos reutilizar esse código em outra tela, precisaríamos copiar e colar o código, o que é uma má prática, pois resultaria em duplicação de código.

Sendo assim, a melhor maneira para adicionar o fundo gradiente é criar uma extensão da ViewController, onde criaremos um método para adicionar um fundo gradiente na tela.

O Swift no iOS com o UIkit é um pouco complicado para trabalhar com elementos como gradiente. O código não é tão simples quanto colocar uma cor de fundo, como fizemos na linha 14 do arquivo HomeViewController.swift, utilizando view.backgroundColor = UIColor().

Começaremos criando uma nova pasta no projeto. Para isso, clicamos sobre TaskyApp com o botão direito do mouse, selecionamos "New Group", e nomeamos como "Extensions".

Nessa pasta, vamos criar um novo arquivo do tipo "Swift File" chamado UIViewController+. O sinal de + ao final é uma boa prática quando trabalhamos com arquivos que são extensões.

UIViewController+.swift:

// código omitido

import Foundation

Construindo a extensão UIViewController

Na linha 10, podemos começar a criar uma extension chamada UIViewController. No escopo dessa extension, adicionaremos um método (func) chamado addGradientBackground().

No momento, o Xcode indica que não consegue encontrar UIViewController, pois ainda precisamos importar o UIkit. Portanto, na linha 8, em vez de import Foundation, usaremos import UIKit.

// código omitido

import UIKit

extension UIViewController {
    func addGradientBackground() {

    }
}

Implementando o método addGradientBackground()

Agora vamos implementar o método addGradientBackground(). Podemos começar definindo uma constante let na linha 12 chamada gradientBackground, que será igual a CAGradientLayer(), basicamente uma camada de gradiente que criamos com essa classe.

Feito isso, vamos definir na linha 13 que gradientBackground.frame será igual a view.bounds, pois queremos que o tamanho do gradiente seja igual ao tamanho total da tela, afinal, ele será o fundo.

// código omitido

extension UIViewController {
    func addGradientBackground() {
        let gradientBackground = CAGradientLayer()
        gradientBackground.frame = view.bounds
    }
}

Em seguida, na linha 14 logo abaixo, vamos definir gradientBackground.colors, onde passaremos as cores que iremos utilizar no gradiente. Isso será um array, então abrimos e fechamos colchetes.

O primeiro elemento do array será a cor do topo, então passaremos UIColor.white. Além disso, precisamos adicionar .cgColor ao final, pois a variável colors exige o parâmetro cgColor.

Feito isso, colocaremos uma vírgula e seguiremos com a segunda opção de UIColor(), com o parâmetro named definido como AssetsConstants.lilac, para aplicar a cor lilás adicionada em Assets.

Como essa cor retorna uma opcional, precisamos utilizar o ponto de interrogação (?) após UIColor(), além do parâmetro cgColor ao final.

Caso haja algum erro com a cor importada, adicionamos dois sinais de interrogação (??) após cgColor para utilizar o tom de roxo normal, ou seja, UIColor.purple.cgColor.

Por fim, precisamos adicionar o método view.layer.insertSublayer() na linha 15. No parâmetro layer, passaremos gradientBackground, variável criada anteriormente; e no parâmetro at, colocaremos o índice zero (0).

O gradiente será a view de fundo, por isso selecionamos o primeiro índice.

// código omitido

extension UIViewController {
    func addGradientBackground() {
        let gradientBackground = CAGradientLayer()
        gradientBackground.frame = view.bounds
        gradientBackground.colors = [UIColor.white.cgColor, UIColor(named: AssetsConstants.lilac)?.cgColor ?? UIColor.purple.cgColor]
        view.layer.insertSublayer(gradientBackground, at: 0)
    }
}

Esse é o código para construir um fundo gradiente. Os processos costumam ser um pouco mais complicados no UIkit, conforme dito anteriormente, mas isso é completamente normal.

Utilizando o método addGradientBackground()

Vamos voltar para o arquivo HomeViewController.swift. Na função viewDidLoad() da linha 14, vamos apagar todo o trecho de view.backgroundColor e chamar o método addGradientBackground().

HomeViewController.swift:

// código omitido

import UIKit

class HomeViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        addGradientBackground()
    }

}

Feito isso, podemo executar o aplicativo com o atalho "Command + R". Dessa forma, já teremos o fundo gradiente aplicado na tela inicial.

Criando a imagem do logotipo

De volta ao projeto no Figma, ainda precisamos inserir as duas primeiras imagens: o logotipo da Tasky e a ilustração principal, ambas na tela inicial.

No Xcode, já temos essas duas imagens no arquivo Assets, então temos tudo preparado. Começaremos criando essas imagens no arquivo HomeViewController.swift.

Logo acima da função viewDidLoad(), na linha 12, escreveremos o código para inserir elementos na tela através da abordagem programática. Portanto, iniciamos declarando uma variável private lazy var chamada logoImageView, que será do tipo UIImageView.

// código omitido

import UIKit

class HomeViewController: UIViewController {

    private lazy var logoImageView: UIImageView = {

    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        addGradientBackground()
    }

}

No escopo da variável, vamos declarar um let chamado imageView, que será igual a UIImageView(), recebendo o parâmetro image definido como UIImage(). Entre os parênteses de UIImage(), o parâmetro named será definido como AssetsConstants.logo.

Note como o AssetsConstants criado anteriormente nos ajuda no processo. Com ele, não precisamos escrever as strings, pois já temos uma referência delas. Essa é uma boa prática muito importante.

// código omitido

private lazy var logoImageView: UIImageView = {
    let imageView = UIImageView(image: UIImage(named: AssetsConstants.logo))
}()

// código omitido

Em seguida, na linha 14, precisamos fazer um imageView.translatesAutoresizingMaskIntoConstraints, que será igual a false, uma vez que utilizamos do View Code.

Logo abaixo, na linha 15, chamaremos imageView.contentMode e definiremos como .scaleAspectFit para a imagem ficar bem encaixada.

Para finalizar, passamos return imageView na linha 16.

// código omitido

private lazy var logoImageView: UIImageView = {
    let imageView = UIImageView(image: UIImage(named: AssetsConstants.logo))
    imageView.translatesAutoresizingMaskIntoConstraints = false
    imageView.contentMode = .scaleAspectFit
    return imageView
}()

// código omitido

Criando a imagem da ilustração principal

Podemos copiar o trecho de código entre as linhas 12 e 17, pois será basicamente o mesmo para a segunda imagem. Após colar o trecho na linha 19, mudaremos o nome de logoImageView para mainIllustrationImageView.

Além disso, na linha 20, em vez de passar logo, passaremos homeIllustration. As outras informações serão iguais para ambas as imagens, então vamos manter os trechos das linhas 21 e 22.

// código omitido

private lazy var mainIllustrationImageView: UIImageView = {
    let imageView = UIImageView(image: UIImage(named: AssetsConstants.homeIllustration))
    imageView.translatesAutoresizingMaskIntoConstraints = false
    imageView.contentMode = .scaleAspectFit
    return imageView
}()

// código omitido

Declarando o método addSubviews()

Agora precisamos adicionar as duas imagens na tela, além de adicionar as constraints para posicioná-las conforme esperado.

Para isso, criaremos dois métodos após a função viewDidLoad() no arquivo HomeViewController.swift. Na linha 31, adicionaremos um private func chamado addSubviews().

No escopo desse método, na linha 32, vamos chamar view.addSubview() recebendo logoImageView entre parênteses. Logo depois, na linha 33, adicionaremos view.addSubview(mainIllustrationImageView).

// código omitido

private func addSubviews() {
    view.addSubview(logoImageView)
    view.addSubview(mainIllustrationImageView)
}

// código omitido

Declarando o método setupConstraints()

Agora, a partir da linha 36, vamos declarar um private func chamado setupConstraints(). No escopo do método, na linha 37, chamaremos NSLayoutConstraint.activate().

Entre os parênteses de activate(), vamos adicionar as constraints. Começaremos chamando logoImageView e colocando uma topAnchor.

Ela será equalTo: view.safeAreaLayoutGuide para pegar a área segura da aplicação que tira a data e a hora, e finalizaremos com um topAnchor, que é a constraint do topo.

Por último, vamos centralizar essa imagem. Para isso, adicionaremos logoImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).

// código omitido

private func setupConstraints() {
    NSLayoutConstraint.activate([
        logoImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
        logoImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
}

// código omitido

Para a segunda imagem, vamos chamar mainIllustrationImageView.topAnchor.constraint() e selecionar a opção com equalTo e constant. Em equalTo, colocaremos logoImageView.bottomAnchor, pois ela ficará abaixo do logo. Como constant, vamos colocar um valor de 8.0.

Da mesma forma, iremos centralizá-la com mainIllustrationImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).

// código omitido

private func setupConstraints() {
    NSLayoutConstraint.activate([
        logoImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
        logoImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),

        mainIllustrationImageView.topAnchor.constraint(equalTo: logoImageView.bottomAnchor, constant: 8.0),
        mainIllustrationImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
}

// código omitido

Por fim, podemos chamar os dois métodos que acabamos de criar na função viewDidLoad(), da linha 26. Na linha 29, chamaremos addSubviews(), e na linha 30, setupConstraints().

// código omitido

override func viewDidLoad() {
    super.viewDidLoad()
    addGradientBackground()
    addSubviews()
    setupConstraints()
}

// código omitido

Ao executar o código com "Command + R", verificamos que, como resultado, recebemos o logotipo e a imagem principal na tela inicial.

Conclusão

Agora que adicionamos as duas imagens na tela e também o fundo gradiente, falta adicionar o texto e o botão. Faremos isso no próximo vídeo!

Sobre o curso iOS: construindo uma lista de tarefas com MVC com View Code

O curso iOS: construindo uma lista de tarefas com MVC com View Code possui 139 minutos de vídeos, em um total de 51 atividades. Gostou? Conheça nossos outros cursos de iOS em Mobile, ou leia nossos artigos de Mobile.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda iOS acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas