Prática 3: Integrando os Componentes Instalados

Assista e acompanhe a prática em sala dos exercícios "Integrando os Componentes Instalados". Execute as instruções conforme a apresentação.

Exercício 1. Integrando o SAMTextView

1.1. Abrir o arquivo Main.Storyboard e localizar o View Controller de Formulário

1.2. Modificar a classe do Text View de Descrição para SAMTextView

1.3. Modificar o Outlet do Text View para corresponder ao novo Tipo

No arquivo ActivityFormViewController.swift modifique o código do Outlet para corresponder ao novo tipo, conforme a listagem abaixo:

@IBOutlet weak var descriptionTextView: UITextView!
@IBOutlet weak var descriptionTextView: SAMTextView!

É necessário incluir a referência para a biblioteca SAMTextView no topo do arquivo:

import SAMTextView

1.4. Alterar o Placeholder no método viewDidLoad

Incluir no método viewDidLoad o código para alterar o campo placeholder do SAMTextView:

override func viewDidLoad() {
    super.viewDidLoad()

    // Configura os componentes
    self.descriptionTextView.placeholder = "Descrição detalhada da atividade..."

    // Código restante do método, não deve ser modificado
    // ...
}

1.5. Execute o App e verifique o placeholder no TextView no Formulário de Atividade


Exercício 2. Integrando o StaticDataTableController

2.1. Abra o arquivo Main.Storyboard e localize o View Controller do Formulário de Atividade

2.2. Criar o Outlet Collection de Células de Repetição

Criar um Outlet Collection para as células de repetição:

  • Quantidade de Repetições
  • Slider de Quantidade
  • Vibração ao Toque

Conforme o código abaixo:

@IBOutlet var repetitionsOptionsCells: [UITableViewCell]!

2.3. Criar o Outlet Colleciton de Células de Tempo Limite

Criar um Outlet Collection para as células de repetição:

  • Limite de Tempo
  • Slider de Quantidade

Conforme o código abaixo:

@IBOutlet var timeLimitOptionsCells: [UITableViewCell]!

2.4. Alterar a Super Classe do View Controller

Modifique a super classe da class ActivityFormViewController no código:

class ActivityFormViewController: UITableViewController {
class ActivityFormViewController: StaticDataTableViewController {

É necessário incluir a referência para a biblioteca StaticDataTableViewController no topo do arquivo:

import StaticDataTableViewController

2.5. Incluir os métodos de apoio

Editar o arquivo ActivityFormViewController.swift para incluir os métodos de apoio abaixo:

/// Esconde ou exibe as células das opções de repetições
func setRepetitionsVisibility(hidden: Bool) {
    self.cells(self.repetitionsOptionsCells, setHidden: hidden)
    self.reloadDataAnimated(true)
}

/// Esconde ou exibe as células das opções de tempo limite
func setTimeLimitVisibility(hidden: Bool) {
    self.cells(self.timeLimitOptionsCells, setHidden: hidden)
    self.reloadDataAnimated(true)
}

2.6. Incluir os Action Methods dos UISwitchs

Incluir Action Metidos para o evento Value Changed dos componentes UISwitch conforme o código abaixo:

@IBAction func repetitionsSwitched(sender: UISwitch) {
    self.setRepetitionsVisibility(!sender.on)
}

@IBAction func timeLimitSwitched(sender: UISwitch) {
    self.setTimeLimitVisibility(!sender.on)
}

2.7. Atualizar o método viewDidLoad para ajustar a exibição dos componentes

Atualizar o método viewDidLoad em ActivityFormViewController.swift de acordo com o código abaixo:

override func viewDidLoad() {
    super.viewDidLoad()

    // Configura os componentes
    self.descriptionTextView.placeholder = "Descrição detalhada da atividade..."

    // Do any additional setup after loading the view.
    if let a = self.activity {
        self.title = "Editar Atividade"
        self.nameTextField.text = a.name
        self.descriptionTextView.text = a.details

        self.repetitionsSwitch.on = (a.repetitions.integerValue > 0)
        // Carrega e configura as opções de repetições
        let repetitionsEnabled = (a.repetitions!.integerValue > 0)
        self.setRepetitionsVisibility(!repetitionsEnabled)
        self.repetitionsSwitch.on = repetitionsEnabled
        self.repetitionsSlider.value = a.repetitions.floatValue
        self.repetitionsLabel.text = a.repetitions.stringValue

        self.timeLimitSwitch.on = (a.timeLimit.integerValue > 0)
        // Carrega e configura as opções de tempo limite
        let timeLimitEnabled = (a.timeLimit!.integerValue > 0)
        self.setTimeLimitVisibility(!timeLimitEnabled)
        self.timeLimitSwitch.on = timeLimitEnabled
        self.timeLimitSlider.value = a.timeLimit.floatValue
        self.timeLimitLabel.text = self.getTimeDescription(a.timeLimit.integerValue)

        // Quantidade de sessões dessa atividade
        let sessions = a.sessions.count
        if sessions > 0 {
            self.historyLabel.text = "\(sessions) " + ((sessions == 1) ? "Sessão" : "Sessões")
        }
    } else {
        self.title = "Nova Atividade"
    }
}

2.8. Execute o App e verifique se a marcação/desmarcação dos Switchs esta funcionando adequadamente


Exercício 3. Integrando o EFCircularSlider

3.1. Criar o arquivo TimeLimitChooserViewController.swift no grupo Views

3.2. Incluir o protocolo TimeLimitChooserDelegate

No arquivo criado incluir o protocolo TimeLimitChooserDelegate conforme o código abaixo:

/// Protocolo que deve ser implementado pelo Delegate do Componente
protocol TimeLimitChooserDelegate {
    // Informa ao Delegate que o componente mudou a seleção de horas
    func timeLimitChooser(chooser: TimeLimitChooserViewController, didChangeTimeLimit seconds: Int)
}

3.3. Incluir a classe TimeLimitChooserViewController

No arquivo criado abaixo do protocolo inserido na tarefa anterior, incluir o código da classe conforme a listagem abaixo:

class TimeLimitChooserViewController : UIViewController {

    //
    // MARK: - Constants

    let baseWidth = CGFloat(320)
    let baseHeight = CGFloat(220)

    //
    // MARK: - Properties

    var sliderHours: EFCircularSlider!
    var sliderMinutes: EFCircularSlider!
    var delegate: TimeLimitChooserDelegate?

}

No topo do arquivo incluir a referência para a biblioteca EFCircularSlider:

import EFCircularSlider

3.4. Incluir o método viewDidLoad

Incluir o método viewDidLoad da classe conforme o código abaixo:

//
// MARK: - View Lifecycle

override func viewDidLoad() {
    super.viewDidLoad()

    // Configura a cor de fundo da View de acordo com o Tint Color
    self.view.backgroundColor = UINavigationBar.appearance().barTintColor

    // Configura o primeiro Slider, de minutos, que será o mais externo
    let sliderHourFrame = CGRect(x: 0, y: 0, width: baseWidth, height: baseHeight)
    self.sliderHours = EFCircularSlider(frame: sliderHourFrame)
    self.sliderHours.unfilledColor = UIColor(red: 23/255.0, green: 47/255.0, blue: 70/255.0, alpha: 1.0)
    self.sliderHours.filledColor = self.view.tintColor
    self.sliderHours.minimumValue = 0
    self.sliderHours.maximumValue = 60
    self.sliderHours.lineWidth = 8
    self.sliderHours.snapToLabels = false
    self.sliderHours.labelFont = UIFont.systemFontOfSize(12.0)
    self.sliderHours.labelColor = self.view.tintColor
    self.sliderHours.handleType = bigCircle
    self.sliderHours.handleColor = self.sliderHours.filledColor

    // Esse array determina as marcações ao longo do círculo do slider
    let hoursArray = ["5", "10", "15", "20", "25", "30", "35", "40", "45", "50", "55", "60"]
    self.sliderHours.setInnerMarkingLabels(hoursArray)
    self.sliderHours.addTarget(self, action:"slidersChanged:", forControlEvents:UIControlEvents.ValueChanged)
    self.view.addSubview(self.sliderHours)

    // Configura o segundo slider, com so minutos, que será mais interno
    let sliderMinutesFrame = CGRectMake(0, 0, 150, 145)
    self.sliderMinutes = EFCircularSlider(frame: sliderMinutesFrame)
    self.sliderMinutes.unfilledColor = UIColor(red: 23/255.0, green: 47/255.0, blue: 70/255.0, alpha: 1.0)
    self.sliderMinutes.filledColor = self.view.tintColor
    self.sliderMinutes.minimumValue = 0
    self.sliderMinutes.maximumValue = 60
    self.sliderMinutes.lineWidth = 8
    self.sliderMinutes.labelFont = UIFont.systemFontOfSize(14.0)
    self.sliderMinutes.labelColor = self.view.tintColor
    self.sliderMinutes.handleType = doubleCircleWithOpenCenter
    self.sliderMinutes.handleColor = self.sliderMinutes.filledColor

    // Determina as marcações ao longo do círculo do slider
    let minutesArray = ["5", "10", "15", "20", "25", "30", "35", "40", "45", "50", "55", "60"]
    self.sliderMinutes.setInnerMarkingLabels(minutesArray)
    self.sliderMinutes.addTarget(self, action:"slidersChanged:", forControlEvents: UIControlEvents.ValueChanged)
    self.view.addSubview(self.sliderMinutes)
    self.sliderMinutes.center = self.sliderHours.center
}

3.5. Incluir o método viewWillLayoutSubviews

Incluir o método viewWillLayoutSubviews conforme a listagem abaixo:

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    // Re-calcula os frames das Views
    self.sliderHours.frame = CGRect(x: (self.view.frame.width / 2) - (self.sliderHours.frame.width / 2),
        y: (self.view.frame.height / 2) - (self.sliderHours.frame.height / 2),
        width: self.sliderHours.frame.width,
        height: self.sliderHours.frame.height)

    self.sliderMinutes.center = self.sliderHours.center
}

3.6. Incluir os demais métodos

Incluir os métodos de apoio e Action Methods conforme a listagem abaixo:

//
// MARK: - Métodos de Apoio

func getTimeLimitSeconds() -> Int {
    return ((Int(self.sliderHours.currentValue) * 60) + Int(self.sliderMinutes.currentValue)) * 60
}

//
// MARK: - Action Methods

func slidersChanged(slider : EFCircularSlider) {
    self.delegate?.timeLimitChooser(self, didChangeTimeLimit: self.getTimeLimitSeconds())
}

3.7. Criar a classe TimeLimitViewCell

Criar a classe TimeLimitViewCell com a super classe UITableViewCell no grupo Views, conforme o código abaixo:

class TimeLimitViewCell: UITableViewCell {

    //
    // MARK: - Propriedades

    var timeLimitChooser: TimeLimitChooserViewController!
    var delegate: TimeLimitChooserDelegate? {
        didSet {
            self.timeLimitChooser.delegate = self.delegate
        }
    }

    //
    // MARK: - Initializers

    required init?(coder aDecoder: NSCoder) {
        self.timeLimitChooser = TimeLimitChooserViewController()
        super.init(coder: aDecoder)
    }

    //
    // MARK: - Outros Métodos

    override var inputView: UIView {
        return self.timeLimitChooser.view
    }

    override func canBecomeFirstResponder() -> Bool {
        return true
    }

    override func resignFirstResponder() -> Bool {
        self.setSelected(false, animated: true)
        return super.resignFirstResponder()
    }

}

3.8. Configurar a propriedade Class da célula de Tempo Limite

Localizar a célula de tempo limite no Formulário e alterar seu Class para TimeLimitViewCell criado na tarefa anterior.

3.9. Excluir a Célula com o Slider de Tempo Limite

3.10. Excluir as referências para o Slider de Tempo Limite

Exclua as referências para o Slider tempo limite conforme o código abaixo:

Outlet:

@IBOutlet weak var timeLimitSlider: UISlider!

Método viewDidLoad:

self.timeLimitSlider.value = a.timeLimit.floatValue

Método timeLimitValueChanged::

@IBAction func timeLimitValueChanged(sender: UISlider) {
    self.timeLimitLabel.text = self.getTimeDescription(Int(sender.value))
}

3.11. Incluir a propriedade para armazenar o tempo selecionado

Inclua a propriedade para armazenar o tempo limite selecionado:

var selectedTimeLimit: Int = 0

E atualize o método setActivityData: para utiliza-lo:

func setActivityData(activity: Activity) {
    activity.name = self.nameTextField.text
    activity.details = self.descriptionTextView.text
    activity.enableVibration = self.vibrateSwitch.on
    activity.repetitions = self.repetitionsSwitch.on ? Int(self.repetitionsSlider.value) : 0
    activity.timeLimit = self.timeLimitSwitch.on ? Int(self.timeLimitSlider.value) : 0
    activity.timeLimit = self.timeLimitSwitch.on ? self.selectedTimeLimit : 0
}  

3.12. Implemente o protocolo TimeLimitChooserDelegate

Atualize a declaração da classe para aderir ao protocolo TimeLimitChooserDelegate:

class ActivityFormViewController: StaticDataTableViewController {
class ActivityFormViewController: StaticDataTableViewController, TimeLimitChooserDelegate {

E inclua a implementação de seus métodos:

//
// MARK: - Time Limit Chooser Delegate

func timeLimitChooser(chooser: TimeLimitChooserViewController, didChangeTimeLimit seconds: Int) {
    self.selectedTimeLimit = seconds
    self.timeLimitLabel.text = self.getTimeDescription(selectedTimeLimit)
}

3.13. Atualize o método tableView:didSelectRowAtIndexPath: para exibir o controle

Atualize o método tableView:didSelectRowAtIndexPath: para apresentar o componente quando a célula de tempo limite for selecionada:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    let indexPathT = (indexPath.section, indexPath.row)
    switch indexPathT {
    case (3, 1):
        let cell = tableView.cellForRowAtIndexPath(indexPath) as! TimeLimitViewCell
        cell.delegate = self
        cell.becomeFirstResponder()
    case (5, 0):
        let alert = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
        alert.addAction(UIAlertAction(title: "Apagar Atividade", style: .Destructive) {
            (action) in
            TraqtDataContext.sharedInstance.activities.delete(self.activity!.activityId)
            self.navigationController?.popViewControllerAnimated(true)
            })
        alert.addAction(UIAlertAction(title: "Cancelar", style: .Cancel, handler: nil))

        self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
        self.presentViewController(alert, animated: true, completion: nil)
    default:
        break
    }
}