Técnico

Desenvolvendo o 1º App para Apple Watch

Watch_Icons

Neste tutorial vamos desenvolver um aplicativo simples de ToDo para Apple Watch,  utilizando  o Xcode 7.1 e WatchKit 2.0.1 , nele listaremos uma serie de itens e vamos poder marca-los como concluido, Todo o código para esse tutorial será apresentado em Objective-C e Swift.

1. Criando o projeto

Abra o Xcode, clique em Create New Xcode Project, em seguida selecione  iOS App with WatchKit App e clique em next (Figura 1).

select_templete

Figura 1

Na janela que é exibida em seguida vamos configurar o nome e o identificador do aplicativo. Nela também podemos selecionar itens adicionais para o projeto, no nosso casso, vamos desmarcar todas as opções e clicar em next (Figura 2).

project_options

Figura 2

Ao final desse primeiro passo, teremos uma hierarquia de arquivo como mostra a Figura 3.

Figura 3

2. Desenhando a Interface

Localize o arquivo Interface.storyboard dentro da pasta WatchKit App, é neste arquivo que vamos desenhar nossa tela, selecionando esse arquivo, sera exibido um interface conforme Figura 4.

interface_storyboard

Figura 4

Essa é a nossa tela principal (única no nosso projeto). Vamos adicionar os objetos necessários para nossa lista de itens do ToDo, o primeiro deles é um Table. Para adicioná-lo vamos localizá-lo na lista de objetos no canto inferior direito da janela do Xcode (Figura 5) e arrastá-lo para dentro da nossa interface, o resultado será como a Figura 6.

object_library

Figura 5

interface_with_table

Figura 6

Como podemos ver, já foi adicionado automaticamente um Table Row Controller e um Group. Vamos agora adicionar dentro do Table Row um objeto do tipo Image, seguindo os mesmo passos, localizamos o objeto na lista e arrastamos o mesmo para dentro do Table Row na nossa interface. O resultado será como na Figura 7.

Figura 7

Figura 7

Precisamos a configurar o tamanho da imagem, no nosso caso vai ter 25×25 pixels, selecionando o objeto Image na interface aparecerá no Inspector (canto superior direito da janela do Xcode) as informações de acordo com a Figura 8, vamos altera-las para que fique como a Figura 9. (caso não aparece essas informações, clique no icone attributes_inspector_icone  – Attributes Inspector).

Vamos alterar os seguintes atributos:

  • Alignment Vertical de Top para Center
  • Size Width e Height de Size To Fit Content para Fixed e fixaremos os valores em 25.
Figura 8

Figura 8

Figura 9

Figura 9

Nossa interface deve estar agora como a Figura 10.

Figura 10

Figura 10

Ainda dentro do Table Row View, vamos adicionar um objeto do tipo Label, seguindo os mesmos passos dos objetos anteriores. Para o label vamos alterar no Attribute Inspector o seguinte item:

  • Alignment Vertical de Top para Center

O Resultado do Attribute Inspector deverá ser como a Figura 11 e da nossa interface, como a Figura 12.

Figura 11

Figura 11

Figura 12

Figura 12

 

3. Criando arquivos adicionais

Neste passo, vamos criar mais dois arquivos, um para controlar as linhas da nossa tabela e outro para controlar cada um dos items do ToDo, nomeando-os respectivamente de ToDoRow e ToDoItem.

Esses arquivos devem ser criados dentro da Pasta WatchKit Extension, para criá-los vamos clicar com o botão direito na pasta, e em seguida na opção New File… (Figura 13).

Figura 13

Figura 13

Na tela seguinte selecionaremos WatchKit Class como o tipo do arquivo a ser adicionado (Figura 14), em seguida vamos nomear o arquivo e selecionar a linguagem desejada. Esse arquivos devem ser subclasse de NSObject (Figura 15).

 

Figura 14

Figura 14

Figura 15

Figura 15

 

Depois que os dois arquivos forem criado a nossa hierarquia de arquivos deve ser parecida com a Figura 16 ou Figura 17, dependendo da linguagem escolhida, respectivamente Objective-C ou Swift.

Figura 16

Figura 16

Figura 17

Figura 17

 

4. Codificando 

Agora vamos escrever o código necessário para cada um desses dois arquivos

Começaremos pelo ToDoItem, criaremos duas propriedade, uma para a saber se o item foi finalizado e outra para o titulo do ToDo, os nomes serão respectivamente, done e title.

  • Objective-C (ToDoItem.h)

[markdown]

“`
#import <Foundation/Foundation.h>

@interface ToDoItem : NSObject

@property (nonatomic) BOOL done;
@property (strong, nonatomic) NSString *title;

@end

“`

[/markdown]

  • Swift (ToDoItem.swift)

[markdown]

“`

import WatchKit

class ToDoItem: NSObject {

var done: Bool = false
var title: String = “”
}

“`

[/markdown]

 

Agora vamos para o ToDoRow, também criaremos duas propriedade, uma para a imagem e outra para o label que definimos anteriormente na interface, os nomes serão respectivamente, imageChecked e labelToDo. Essa duas propriedades devem ter o atributo IBOutlet, pois elas serão “conectadas” com os objetos da interface.

  • Objective-C (ToDoRow.m)

[markdown]

“`
#import “ToDoRow.h”

@interface ToDoRow ()

@property (unsafe_unretained, nonatomic) IBOutlet WKInterfaceImage *imageChecked;
@property (unsafe_unretained, nonatomic) IBOutlet WKInterfaceLabel *labelToDo;

@end

@implementation ToDoRow

@end

“`

[/markdown]

  • Swift (ToDoRow.swift)

[markdown]

“`

import WatchKit

class ToDoRow: NSObject {

@IBOutlet var imageChecked: WKInterfaceImage!
@IBOutlet var labelToDo: WKInterfaceLabel!

}

“`

[/markdown]

Ainda no ToDoRow, vamos criar um método chamado configRowWithItempara configurarmos cada uma das linhas da nossa tabela, esse método receberá um ToDoItem como parâmetro.

  • Objective-C (ToDoRow.h)

[markdown]

“`
#import <WatchKit/WatchKit.h>
#import “ToDoItem.h”

@interface ToDoRow : NSObject

-(void)configRowWithItem:(ToDoItem *)toDoItem;

@end

“`

[/markdown]

  • Objective-C (ToDoRow.m)

[markdown]

“`

@implementation ToDoRow

-(void)configRowWithItem:(ToDoItem *)toDoItem
{
if(!toDoItem.done) //Se nao estiver selecionado nao seta imagem
[self.imageChecked setImage:nil];
else //seta imagem de checked
[self.imageChecked setImage:[UIImage imageNamed:@”todo_done”]];

//seta o titulo do ToDo
[self.labelToDo setText:toDoItem.title];
}

@end

“`

[/markdown]

  • Swift (ToDoRow.swift)

[markdown]

“`

import WatchKit

class ToDoRow: NSObject {

@IBOutlet var imageChecked: WKInterfaceImage!
@IBOutlet var labelToDo: WKInterfaceLabel!

func configRowWithItem(todoItem: ToDoItem) {

if !todoItem.done { //Se nao estiver selecionado nao seta imagem
imageChecked.setImage(UIImage(named: “”))
}
else { //seta imagem de checked
imageChecked.setImage(UIImage(named: “todo_done”))
}

//seta o titulo do ToDo
labelToDo.setText(todoItem.title)

}
}

“`

[/markdown]

 

Feito isso, precisamos codificar o comportamento da nossa tabela, isso sera feito no arquivo InterfaceController, que é o controladora da nossa interface e foi criado junto com o projeto.

Primeiramente vamos criar duas propriedade, uma para se conectar com o objeto Table da nossa interface e outro, um array para armazenar os itens do ToDo que vamos criar, os nomes serão respectivamente tabletoDoItems. Lembrando que a propriedade table precisa ter o atributo IBOutlet.

  • Objective-C (InterfaceController.m)

[markdown]

“`
#import “InterfaceController.h”
#import “ToDoRow.h”
#import “ToDoItem.h”

@interface InterfaceController()

@property (unsafe_unretained, nonatomic) IBOutlet WKInterfaceTable *table;
@property (strong, nonatomic) NSMutableArray *toDoItems;

@end

@implementation InterfaceController

– (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// Configure interface objects here.
}

– (void)willActivate {
// This method is called when watch view controller is about to be visible to user
[super willActivate];
}

– (void)didDeactivate {
// This method is called when watch view controller is no longer visible
[super didDeactivate];
}

@end

“`

[/markdown]

  • Swift (InterfaceController.swift)

[markdown]

“`

import WatchKit
import Foundation

class InterfaceController: WKInterfaceController {

@IBOutlet var table: WKInterfaceTable!
var toDoItems = [ToDoItem]()

override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)

// Configure interface objects here.
}

override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}

override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}

}

“`

[/markdown]

Vamos criar agora, dois novos métodos nesse mesmo arquivo, um para criar os items do ToDo e um para popular a nossa tabela na interface, os métodos terão os seguintes nomes, createTodoList e setupTable.

  • Objective-C (InterfaceController.m)

[markdown]

“`
-(void)setupTable
{
//Seta o numero de item da lista
[self.table setNumberOfRows:self.toDoItems.count withRowType:@”ToDoRow”];

//Para cada item da lista configura a linha na tabela
for (NSInteger idx = 0; idx < self.table.numberOfRows; idx++) {
ToDoRow *toDoRow = [self.table rowControllerAtIndex:idx];

[toDoRow configRowWithItem:self.toDoItems[idx]];
}
}

-(void)createTodoList
{
//Cria 5 itens e inicializa com um titulo padrao e como nao finalizado

[self setToDoItems:[NSMutableArray new]];

for (NSInteger idx = 1; idx <= 5; idx++) {
ToDoItem *newItem = [[ToDoItem alloc] init];
[newItem setDone:NO];
[newItem setTitle:[NSString stringWithFormat:@”To Do Item %ld”, (long)idx]];

[self.toDoItems addObject:newItem];
}
}

“`

[/markdown]

  • Swift (InterfaceController.swift)

[markdown]

“`

func setupTable() {

//Seta o numero de item da lista
table.setNumberOfRows(toDoItems.count, withRowType: “ToDoRow”)

//Para cada item da lista configura a linha na tabela
for idx in 0…table.numberOfRows {
if let toDoRow = table.rowControllerAtIndex(idx) as? ToDoRow {
toDoRow.configRowWithItem(toDoItems[idx])
}
}
}

func createTodoList() {

//Cria 5 itens e inicializa com um titulo padrao e como nao finalizado
for idx in 1…5 {

let newItem = ToDoItem()

newItem.done = false
newItem.title = “To Do Item \(idx)”

toDoItems.append(newItem)

}
}
“`

[/markdown]

Precisamos agora fazer as chamadas para esses dois métodos, para isso vamos alterar o método awakeWithContext que vem codificado por padrão nessa classe de controle de interface.

  • Objective-C (InterfaceController.m)

[markdown]

“`
– (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// Configure interface objects here.

//cria os itens do ToDo
[self createTodoList];
//Preenche a tabela
[self setupTable];
}

“`

[/markdown]

  • Swift (InterfaceController.swift)

[markdown]

“`
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)

// Configure interface objects here.

//cria os itens do ToDo
createTodoList()
//Preenche a tabela
setupTable()
}
“`

[/markdown]

Agora vamos criar o nosso ultimo método. Esse é um método da classe Table que é chamado quando uma linha da tabela é selecionada esse método tem as seguintes assinaturas:

-(void)table:(WKInterfaceTable *)table didSelectRowAtIndex:(NSInteger)rowIndex 

override func table(table: WKInterfaceTable, didSelectRowAtIndex rowIndex: Int)

para Objective-C e Swift respectivamente.

  • Objective-C (InterfaceController.m)

[markdown]

“`
-(void)table:(WKInterfaceTable *)table didSelectRowAtIndex:(NSInteger)rowIndex
{
//Marca como Feito ou não feito (inverte o valor a cada click)
BOOL done = ((ToDoItem *)self.toDoItems[rowIndex]).done;
[self.toDoItems[rowIndex] setDone:!done];

//Preenche a tabela
[self setupTable];
}

“`

[/markdown]

  • Swift (InterfaceController.swift)

[markdown]

“`
override func table(table: WKInterfaceTable, didSelectRowAtIndex rowIndex: Int) {

//Marca como Feito ou não feito (inverte o valor a cada click)
let done: Bool = toDoItems[rowIndex].done
toDoItems[rowIndex].done = !done

//Preenche a tabela
setupTable()
}
“`

[/markdown]

Com isso finalizamos a parte de codificação

 

5. Conectando o código com a interface

É preciso agora fazermos os links das classes e das propriedades que criamos na codificação, com os objetos criados na interface, vamos começar com as classes.

Selecione novamente o arquivo interface.storyboard dentro da pasta WatchKit App, em seguida selecione Table Row Controller nas hierarquia de objetos, conforme Figura 18

Figura 18

No inspector, selecione o  Attributes Inspector attributes_inspector_icone ), nele vamos configurar o seguinte atributo (Figura 19):

  • Identifier  para ToDoRow
Figura 19

Figura 19

Esse atributo é usado no método setupTable da classe InterfaceController codificado anteriormente, no parametro WithRowType na hora que setamos o número de linhas da tabela.

  • Objective-C 

[markdown]

“`
[self.table setNumberOfRows:self.toDoItems.count withRowType:@”ToDoRow”];
“`

[/markdown]

  • Swift 

[markdown]

“`
table.setNumberOfRows(toDoItems.count, withRowType: “ToDoRow”)
“`

[/markdown]

Ainda no inspector selecione o Identity Inspector (identity_inspector), vamos configurar classe correspondente a nossa Table Row setando o seguinte atributo (Figura 20):

Figura 20

Figura 20

Nosso próximo passo é fazer a conexão dos objetos da interface (Table, Image e Label) com as propriedades das classes.
A propriedade table foi definida na classe InterfaceController, então vamos selecionar na nossa hierarquia de objetos o item Interface Controller, conforme Figura 21.

Figura 21

Figura 21

No inspector vamos selecionar o Connections Inspector (connections_inspector_icon), nele temos na seção Outlets a nossa propriedade table (Figura 22).

Figura 22

Figura 22

Clique no circulo ao lado direito da propriedade table e arraste até o item Table na hierarquia de objetos, conforme Figura 23.

Figura 23

Figura 23

O resultado da conexão deve ser igual a Figura 24 , propriedade table conectada ao objeto Table.

connections_inspector_table_02

Figura 24

Precisamos repetir esse processo para os outros dois objetos (Image e Label), as propriedades para ambos foram definidas na classe ToDoRow, então vamos selecionar o Objeto ToDoRow na hierarquia de objetos e fazer as conexões conforme Figuras 25 e 26.

Figura 25

Figura 25

Figura 26

Figura 26

O resultado das novas conexões é mostrado na Figura 27.

Figura 27

Figura 27

Com todas as conexões prontas, para finalizar vamos adicionar as imagens de Checked ao nosso projeto, as imagens estão disponíveis aqui.

Para adicioná-las selecione o arquivo Assets.xcassets dentro da pasta WatchKit Extension (Figura 28).

assets_xcassets

Figura 28

Abra o arquivo .zip das imagens e arreste todas elas para o xcode, conforme Figura 29.

Figura 29

Figura 29

As imagens devem ter o mesmo nome que esta sendo utilizado no método configRowWithItem da classe ToDoRow.

  • Objective-C 

[markdown]

“`
[self.imageChecked setImage:[UIImage imageNamed:@”todo_done”]];
“`

[/markdown]

  • Swift 

[markdown]

“`
imageChecked.setImage(UIImage(named: “todo_done”))
“`

[/markdown]

 

6. Rodando o App no Emulador

Para rodar o App precisamos selecionar o schema, no canto esquerdo da barra de ferramentas do xcode, que vai ser usado. O schema que vamos usar é WatchKit App->iPhone 6s + Apple Watch 30mm (Figura 30).

Figura 30

Figura 30

Agora é só clicar em Run (xcode_play). As Figuras 31, 32 e 33 mostram o resultado do Aplicativo no emulador do Apple Watch.

Figura 31

Figura 31

Figura 32

Figura 32

Figura 33

Figura 33

 

O código fonte do aplicativo, em Objective-C e Swift pode ser baixado aqui.

1 Comments

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Compartilhe isso: