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).
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).
Ao final desse primeiro passo, teremos uma hierarquia de arquivo como mostra a 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.
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.
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.
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).
Vamos alterar os seguintes atributos:
Nossa interface deve estar agora como a 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:
O Resultado do Attribute Inspector deverá ser como a Figura 11 e da nossa interface, como a 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).
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).
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.
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.
[markdown]
“`
#import <Foundation/Foundation.h>
@interface ToDoItem : NSObject
@property (nonatomic) BOOL done;
@property (strong, nonatomic) NSString *title;
@end
“`
[/markdown]
[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.
[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]
[markdown]
“`
import WatchKit
class ToDoRow: NSObject {
@IBOutlet var imageChecked: WKInterfaceImage!
@IBOutlet var labelToDo: WKInterfaceLabel!
}
“`
[/markdown]
Ainda no ToDoRow, vamos criar um método chamado configRowWithItem, para configurarmos cada uma das linhas da nossa tabela, esse método receberá um ToDoItem como parâmetro.
[markdown]
“`
#import <WatchKit/WatchKit.h>
#import “ToDoItem.h”
@interface ToDoRow : NSObject
-(void)configRowWithItem:(ToDoItem *)toDoItem;
@end
“`
[/markdown]
[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]
[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 table e toDoItems. Lembrando que a propriedade table precisa ter o atributo IBOutlet.
[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]
[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.
[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]
[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.
[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]
[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.
[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]
[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
No inspector, selecione o Attributes Inspector ( ), nele vamos configurar o seguinte atributo (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.
[markdown]
“`
[self.table setNumberOfRows:self.toDoItems.count withRowType:@”ToDoRow”];
“`
[/markdown]
[markdown]
“`
table.setNumberOfRows(toDoItems.count, withRowType: “ToDoRow”)
“`
[/markdown]
Ainda no inspector selecione o Identity Inspector (), vamos configurar classe correspondente a nossa Table Row setando o seguinte atributo (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.
No inspector vamos selecionar o Connections Inspector (), nele temos na seção Outlets a nossa propriedade table (Figura 22).
Clique no circulo ao lado direito da propriedade table e arraste até o item Table na hierarquia de objetos, conforme Figura 23.
O resultado da conexão deve ser igual a Figura 24 , propriedade table conectada ao objeto Table.
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.
O resultado das novas conexões é mostrado na 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).
Abra o arquivo .zip das imagens e arreste todas elas para o xcode, conforme Figura 29.
As imagens devem ter o mesmo nome que esta sendo utilizado no método configRowWithItem da classe ToDoRow.
[markdown]
“`
[self.imageChecked setImage:[UIImage imageNamed:@”todo_done”]];
“`
[/markdown]
[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).
Agora é só clicar em Run (). As Figuras 31, 32 e 33 mostram o resultado do Aplicativo no emulador do Apple Watch.
O código fonte do aplicativo, em Objective-C e Swift pode ser baixado aqui.
[…] Nessa segunda parte, vou mostrar como fazer a comunicação entre o App do iPhone e o App do Watch. Vou continuar a partir do projeto do post anterior (Desenvolvendo o 1º App para Apple Watch) . […]