Olá povo,
Mais vídeo-post aqui no blog. Desta vez, falando sobre Storyboard, um novo recurso do iOS 5 SDK. Com ele podemos criar todo o fluxo navegacional da nossa aplicação com apenas alguns cliques.
Espero que gostem,
Qualquer dúvida, deixem seus comentários.
4br4ç05,
nglauber
Mostrando postagens com marcador UITableVIewController. Mostrar todas as postagens
Mostrando postagens com marcador UITableVIewController. Mostrar todas as postagens
sexta-feira, 11 de maio de 2012
sábado, 14 de abril de 2012
iOS: Lendo XML
Olá povo,
Neste post vou mostrar como ler arquivos XML em aplicações iOS. O XML que estou lendo, eu baixei no site do livro Google Android do Ricardo Lecheta (eu tento, mas não deixo o Android :)
O modelo do estrutura do XML que iremos ler é apresentado abaixo:

Como você deve ter observado, o carro descrito no XML tem os atributos nome, desc, url_info e url_foto. Vamos criar uma classe que representará esse objeto em código.
Vamos agora a implementação da tela (lembrando que só estamos mostrando os métodos alterados):
Feito isso, precisamos fazer alguns ajustes no NIB. Abra o NGViewController.xib e remova a UIView e adicione uma UITableViewController. Ligue esse componente ao Outlet da propriedade view, e o dataSource e delegate.
Além disso, alterei também a propriedade "Top Bar" para "Navigation Bar". Feito isso, podemos rodar nossa aplicação. O resultado é apresentado abaixo.
Qualquer dúvida, deixem seus comentários.
4br4ç05,
nglauber
Neste post vou mostrar como ler arquivos XML em aplicações iOS. O XML que estou lendo, eu baixei no site do livro Google Android do Ricardo Lecheta (eu tento, mas não deixo o Android :)
O modelo do estrutura do XML que iremos ler é apresentado abaixo:
<?xml version="1.0" encoding="utf-8"?> <carros> <carro> <nome>Modelo do Carro</nome> <desc>Descrição do Carro</desc> <url_info>http://www.ferrari.com/</url_info> <url_foto>http://www.livroandroid.com.br/</url_foto> </carro> ... </carros>Crie um novo projeto no Xcode utilizando o template "Single View Application". Agora acesse o site do livro e baixe o XML, em seguida adicione-o ao seu projeto no Xcode na pasta "Supporting Files". A estrutura do projeto (no final) deve ficar conforme abaixo:

Como você deve ter observado, o carro descrito no XML tem os atributos nome, desc, url_info e url_foto. Vamos criar uma classe que representará esse objeto em código.
// Carro.h --------------------------------------- #import <Foundation/Foundation.h> @interface Carro : NSObject @property (strong, nonatomic) UIImage *image; @property (strong, nonatomic) NSString *nome; @property (strong, nonatomic) NSString *descricao; @property (strong, nonatomic) NSString *urlInfo; @property (strong, nonatomic) NSString *urlFoto; @end // Carro.m --------------------------------------- #import "Carro.h" @implementation Carro @synthesize nome, descricao, urlFoto, urlInfo, image; @endVou alterar o AppDelegate da aplicação para ficar desta forma:
// NGAppDelegate.h ------------------------------- #import <UIKit/UIKit.h> @class NGViewController; @interface NGAppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) UINavigationController *navigationController; @end // NGAppDelegate.m ------------------------------- #import "NGAppDelegate.h" #import "NGViewController.h" @implementation NGAppDelegate @synthesize window = _window; @synthesize navigationController; - (BOOL)application: (UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions{ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; NGViewController *viewController = [[NGViewController alloc] initWithNibName: @"NGViewController" bundle:nil]; navigationController = [[UINavigationController alloc] initWithRootViewController:viewController]; self.window.rootViewController = self.navigationController; [self.window makeKeyAndVisible]; return YES; } // Outros métodos não alterados @endNesse template, a aplicação é criada com uma UIViewController simples. Vamos utilizar uma UITableViewController que listará os dados lidos através de um objeto da class NSXMLParser. Sua utilização é bem similar ao SAX do Java, e teremos que implementar um protocolo NSXMLParserDelegate, e a medida que as tags são lidas os métodos desse protocolo são chamados.
#import <UIKit/UIKit.h> #import "Carro.h" @interface NGViewController : UITableViewController <NSXMLParserDelegate>{ NSMutableArray *carros; Carro *carro; NSString *currTag; } @endUm NSMutableArray armazenará os objetos Carro criados a partir da leitura do XML. Durante o parser do XML, precisamos saber que tag está sendo lida, para tal setarmos o atributo currTag com tag que corresponde a propriedade da classe Carro. Por exemplo, quando o parser encontrar uma tag "carro", criamos um objeto Carro, já quando encontramos uma tag "nome", devemos definir o a propriedade nome do objeto carro. Por fim, ao encontrar a tag "/carro" devemos adicionar o objeto carro na lista.
Vamos agora a implementação da tela (lembrando que só estamos mostrando os métodos alterados):
#import "NGViewController.h" #import "Carro.h" @implementation NGViewController - (void)viewDidLoad{ [super viewDidLoad]; self.title = @"Carros"; carros = [[NSMutableArray alloc] init]; // Pega o caminho do arquivo XML NSString *xmlPath = [[NSBundle mainBundle] pathForResource:@"carros" ofType:@"xml"]; // Obtém os bytes do arquivo NSData *xmlData = [NSData dataWithContentsOfFile:xmlPath]; // Cria o objeto que fará o parser do XML NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:xmlData]; [xmlParser setDelegate:self]; [xmlParser parse]; } // Métodos chamado quando NSXMLParser // inicia a leitura de uma TAG -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { currTag = elementName; // Se achou a TAG carro, crie um novo objeto if ([currTag compare:@"carro"] == NSOrderedSame){ carro = [[Carro alloc] init]; } } // Método chamado quando vai ler o // conteúdo da TAG -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { if ([currTag compare:@"nome"] == NSOrderedSame && carro.nome == nil){ carro.nome = string; } else if ([currTag compare:@"desc"] == NSOrderedSame && carro.descricao == nil){ carro.descricao = [string stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]; } else if ([currTag compare:@"url_info"] == NSOrderedSame && carro.urlInfo == nil){ carro.urlInfo = [string stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]; } else if ([currTag compare:@"url_foto"] == NSOrderedSame && carro.urlFoto == nil){ carro.urlFoto = [string stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]; } } // Método chamado quando termina de ler uma tag -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { // Se a tag lida for "carro", adiciona à lista if ([elementName compare:@"carro"]==NSOrderedSame){ [carros addObject:carro]; } } // Método de UITableViewController -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [carros count]; } -(NSInteger)numberOfSectionsInTableView: (UITableView *)tableView { return 1; } -(UITableViewCell *)tableView:(UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; } Carro *_carro = [carros objectAtIndex:indexPath.row]; cell.textLabel.text = _carro.nome; cell.detailTextLabel.text = _carro.urlInfo; return cell; } -(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath { // Obtém o carro da linha selecionada Carro *_carro = [carros objectAtIndex:indexPath.row]; // Abre o site do carro selecionado NSURL *url = [NSURL URLWithString:_carro.urlInfo]; [[UIApplication sharedApplication] openURL:url]; } @endO código acima está comentado e parte relacionada com a UITableViwController foi detalhada nesse post aqui.
Feito isso, precisamos fazer alguns ajustes no NIB. Abra o NGViewController.xib e remova a UIView e adicione uma UITableViewController. Ligue esse componente ao Outlet da propriedade view, e o dataSource e delegate.


4br4ç05,
nglauber
sábado, 31 de março de 2012
iOS: UITableView
Olá povo,
Depois de estudar por algumas vezes a programação para a plataforma iOS, resolvi escrever uma série de posts sobre o assunto. Como eu já fiz um "Hello World" e um exemplo básico de tratamento de evento (aqui e aqui respectivamente) vou começar falando do componente UITableView. Esse componente serve para exibir informações em uma lista.
Vamos começar criando um novo projeto no XCode. Selecione File > New > New Project... Na janela que for exibida, selecione Empty Application. Depois preencha os campos conforme a imagem abaixo.
Clique em Next e depois selecione em que diretório deseja salvar o projeto e clique em Create. Será criado um projeto vazio com a estrutura mostrada abaixo:
Neste momento o projeto não faz nada, então vamos criar a primeira tela que exibirá uma lista de nomes. Para tal, clique com o botão direito sobre o projeto e selecione New File...
Selecione UIViewController subclass e clique em Next. No campo Class, preencha com ListagemViewController e em Subclass of, coloque UITableViewController. Clique em Next e em seguida, Create.
Criada a classe que representará a primeira tela da aplicação vamos alterar o NGAppDelegate para instanciar nossa tela. No arquivo .h adicione a propriedade do tipo UINavigationController. Ela servirá para abrirmos uma outra tela e já controlar o fluxo entre elas.
Neste ponto, você já pode mandar rodar a aplicação, mas não teremos nada para listar. Então vamos a implementação da nossa listagem. No arquivo ListagemViewController.h, declare um array chamado nomes, conforme abaixo:
O último método que alteramos foi o tableView:cellForRowAtIndexPath, ele cria um objeto UITableViewCell para cada item da lista. Para evitar a criação de muitos objetos ele tenta reaproveitar linhas que não estejam mais visíveis na tela. Isso é feito no método dequeueReusableCellWithIdentifier:CellIdentifier. Caso não haja uma linha pra reciclar, criamos uma UITableViewCell com o estilo padrão (UITableViewCellStyleDefault). Em seguida, alteramos o texto da UITableViewCell (que internamente contém um UILabel) utilizando o nosso array de nomes. Para obter a posição a ser exibida, utilizamos a propriedade row o parâmetro indexPath. Pronto! Basta rodar nossa aplicação, e o resultado deverá ficar como abaixo:
Vamos criar uma tela para exibir o item selecionado. Botão direito no projeto, New File... Selecione UIViewController subclass (como fizemos anteriormente) e clique em Next. O nome da classe será DetalheViewController e será subclasse de UIViewController. Marque a opção With XIB for user interface. Clique em Next e depois em Create.
Abra o DetalheViewController.xib e arraste um Label para a tela e faça os ajustes de posicionamento e tamanho que desejar. Em seguida, vamos criar o IBOutlet para esse label: clique com o botão direito sobre o botão, e em Referencing Outlets clique em New Referencing Outlet e arraste para o arquivo .h.
Será exibido um popup para preencher o nome do nosso Outlet. Preencha com txtDetalhe e clique em Connect. Em seguida, vou adicionar a propriedade "texto" para essa tela que será atribuída pela tela de listagem. Quando clicarmos em um item da lista, criaremos uma instância de DetalheViewController a atribuiremos essa propriedade com o item selecionado da lista. O arquivos .h e .m deverão ficar como abaixo (lembrando só listamos o que foi modificado).
Podemos notar que o navigation controller já coloca um botão para voltarmos para a tela anterior.
Em breve devo colocar mais posts sobre iOS. Qualquer dúvida, deixem seus comentários.
4br4ç05,
nglauber
Depois de estudar por algumas vezes a programação para a plataforma iOS, resolvi escrever uma série de posts sobre o assunto. Como eu já fiz um "Hello World" e um exemplo básico de tratamento de evento (aqui e aqui respectivamente) vou começar falando do componente UITableView. Esse componente serve para exibir informações em uma lista.
Vamos começar criando um novo projeto no XCode. Selecione File > New > New Project... Na janela que for exibida, selecione Empty Application. Depois preencha os campos conforme a imagem abaixo.



#import <UIKit/UIKit.h> @interface NGAppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) UINavigationController *navegador; @endNo arquivo .m já foram criados alguns métodos pelo template do XCode, mas só vamos mexer no application:didFinishLaunchingWithOptions.
#import "NGAppDelegate.h" #import "ListagemViewController.h" @implementation NGAppDelegate @synthesize window = _window; @synthesize navegador; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)opts { self.window = [[UIWindow alloc] initWithFrame:[ [UIScreen mainScreen] bounds]]; ListagemViewController *lista = [[ListagemViewController alloc] init]; navegador = [[UINavigationController alloc] initWithRootViewController:lista]; self.window.backgroundColor = [UIColor whiteColor]; self.window.rootViewController = navegador; [self.window makeKeyAndVisible]; return YES; }Nesse método instanciamos a nossa tela, e em seguida instanciamos o UiNavigationController passando a nossa tela como tela "raiz", ou seja, a principal. Depois associamos o UINavigationController ao objeto UIWindow, que representa a tela do aparelho.
Neste ponto, você já pode mandar rodar a aplicação, mas não teremos nada para listar. Então vamos a implementação da nossa listagem. No arquivo ListagemViewController.h, declare um array chamado nomes, conforme abaixo:
#import <UIKit/UIKit.h> @interface ListagemViewController : UITableViewController { NSArray *nomes; } @endComo podemos observar, nossa classe herda de UITableViewController. Essa classe implementa dois protocolos (que em Java são interfaces) UITableViewDelegate e UITableViewDataSource. O primeiro trata de eventos disparados pela lista e o segundo define métodos que irão prover informações para a lista. Ao abrirmos o arquivo, podemos notar que temos vários métodos implementados, por isso só vou colocar no código abaixo os métodos que teremos que modificar.
#import "ListagemViewController.h" @implementation ListagemViewController #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.title = @"Listagem"; nomes = [NSArray arrayWithObjects: @"Nelson", @"Glauber", @"Vasconcelos", @"Leal", nil]; } // ... um monte de métodos :) #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView: (UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return nomes.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } cell.textLabel.text = [nomes objectAtIndex:indexPath.row]; return cell; } @endNo método viewDidLoad, inicializamos nossa lista de nomes e alteramos o título da tela. Já no método numberOfSectionsInTableView retornamos a quantidade de sessões que a lista terá. As sessões servem para agrupar opções de uma lista, mas no nosso caso, teremos apenas uma. No método tableView:numberOfRowsInSection retornamos quantas linhas têm cada sessão, como só temos uma, retornamos a quantidade de itens do nosso array de pessoas.
O último método que alteramos foi o tableView:cellForRowAtIndexPath, ele cria um objeto UITableViewCell para cada item da lista. Para evitar a criação de muitos objetos ele tenta reaproveitar linhas que não estejam mais visíveis na tela. Isso é feito no método dequeueReusableCellWithIdentifier:CellIdentifier. Caso não haja uma linha pra reciclar, criamos uma UITableViewCell com o estilo padrão (UITableViewCellStyleDefault). Em seguida, alteramos o texto da UITableViewCell (que internamente contém um UILabel) utilizando o nosso array de nomes. Para obter a posição a ser exibida, utilizamos a propriedade row o parâmetro indexPath. Pronto! Basta rodar nossa aplicação, e o resultado deverá ficar como abaixo:

Abra o DetalheViewController.xib e arraste um Label para a tela e faça os ajustes de posicionamento e tamanho que desejar. Em seguida, vamos criar o IBOutlet para esse label: clique com o botão direito sobre o botão, e em Referencing Outlets clique em New Referencing Outlet e arraste para o arquivo .h.

#import <UIKit/UIKit.h> @interface DetalheViewController : UIViewController @property (weak, nonatomic) IBOutlet UILabel *txtDetalhe; @property (strong, nonatomic) NSString *texto; @end
#import "DetalheViewController.h" @implementation DetalheViewController @synthesize txtDetalhe, texto; - (void)viewDidLoad { [super viewDidLoad]; txtDetalhe.text = texto; }Estamos quase lá. Agora volte ao arquivo ListagemController.m implemente o método tableView:didSelectRowAtIndexPath que é o método chamado quando clicamos em um item da lista.
// Adicionar import no começo do arquivo #import "DetalheViewController.h" - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { DetalheViewController *detailViewController = [[DetalheViewController alloc] initWithNibName: @"DetalheViewController" bundle:nil]; detailViewController.texto = [nomes objectAtIndex:indexPath.row]; [self.navigationController pushViewController: detailViewController animated:YES]; }O método acima instancia nosso DetalheViewController passando o arquivo *.xib (sem a extensão), em seguida atribui a propriedade texto e utiliza o navigationController (que criamos no AppDelegate) para exibir a tela. O resultado pode ser visto abaixo:

Assinar:
Postagens (Atom)