Mostrando postagens com marcador browser. Mostrar todas as postagens
Mostrando postagens com marcador browser. Mostrar todas as postagens

sábado, 30 de junho de 2012

iOS: Dicas

Olá povo,

Como tô mexendo muito com iOS ultimamente vou registrar aqui algumas pequenas dicas no desenvolvimento de aplicações para iOS.

Dica 1 - Adicionando botões na navigation bar dinâmicamente
UIBarButtonItem *saveButton = [[UIBarButtonItem alloc]
  initWithTitle:@"Salvar" 
  style:UIBarButtonItemStyleDone 
  target:self action:@selector(salvarDados)];
[self.navigationItem setRightBarButtonItem:saveButton];

Dica 2 - Ocultando o teclado virtual

O teclado virtual do iOS é exibido automaticamente quando você clica em uma caixa de texto (UITextFiedl), se tornando o "primeiro a responder" (firstResponder) a eventos de toque. Entretanto para fechá-la você vai codificar um pouquinho. Digamos que em uma tela você tenha 3 caixas de texto. Quando o usuário estiver na primeira caixa de texto ele terá a opção de pular para o próximo campo clicando no botão Next no teclado virtual. Para habilitar esse botão altere a propriedade Return Button do TextField para Next. Faça o mesmo no segundo (e nos outros que você precisar). No último coloque Done na mesma propriedade.
Agora ligue o evento Did End On Exit de todas as caixas de texto para o método abaixo.

- (IBAction)hideKeyboard:(id)sender {
  if ([sender isEqual:edtName] == YES){
    [edtAddress becomeFirstResponder];
  } else if ([sender isEqual:edtAddress] == YES){
    [edtPhone becomeFirstResponder];
  } else {
    [edtName resignFirstResponder];
    [edtAddress resignFirstResponder];
    [edtPhone resignFirstResponder];
  }
}
Isso resolve o problema da navegação. Mas uma coisa comum é, ao clicarmos fora da caixa de texto, o teclado desaparecer. Para fazer isso, clique na View da tela e mude seu tipo de classe de UIView para UIControl. Depois associe o evento Touch Up Inside para o método acima.
O parâmetro sender identifica qual componente disparou o evento. Se não foi nenhum dos dois primeiros TextFields ocultamos o teclado chamando o método resignFirstResponder (o TextField agora é o "primeiro respondedor"). Pronto! Agora ao clicar em qualquer área da tela, o teclado desaparecerá.

Dica 3 - Editando células da UITableView

Quando precisamos, em algum tipo de listagem, excluir um registro, podemos recorrer a um recurso bacana do iOS: deslizar sobre célula. Quando isso acontece o método tableView:editingStyleForRowAtIndexPath é chamado. Aqui podemos retornar um estilo de edição para a célula: UITableViewCellEditingStyleDelete ou UITableViewCellEditingStyleInsert.
-(UITableViewCellEditingStyle)tableView:
    (UITableView *)tableView 
  editingStyleForRowAtIndexPath:
    (NSIndexPath *)indexPath{

    return UITableViewCellEditingStyleDelete;
}
Quando deslizar o dedo para a direita sobre a célula, aparecerá ao botão Delete na célula. Para tratar o evento desse botão devemos implementa o método abaixo:
-(void)tableView:(UITableView *)tableView 
 didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath {
}
Uma outra opção é colocar utilizar o código abaixo ao clicar em um UIBarButton.
-(void)habilitarExcluir:(id)sender {
  [self.tableView setEditing:
    !self.tableView.editing animated:YES];
}
E realizar o código da exclusão no método abaixo:
- (void)tableView:(UITableView *)tableView 
  commitEditingStyle:(UITableViewCellEditingStyle)editingStyle 
  forRowAtIndexPath:(NSIndexPath *)indexPath {

  if (editingStyle == 
    UITableViewCellEditingStyleDelete) {
  }   
}

Dica 4 - Abrindo uma URL no Browser

O código abaixo também aplica-se a telefone (tel:88990099) e mapas...
NSURL *url = [NSURL URLWithString:
  @"http://nglauber.blogspot.com"];
[[UIApplication sharedApplication] openURL:url];

Dica 5 - iPhone ou iPad?

Em uma aplicação Universal (que roda em iPhone e iPad) para checar se o device é um iPhone (ou iPod) ou iPad utilizamos o código abaixo:
if ([[UIDevice currentDevice] userInterfaceIdiom] == 
  UIUserInterfaceIdiomPhone) {
  //iPhone ou iPod
} else {
  // iPad
}

Dica 6 - Salvando Objetos com NSUserDefaults

Para salvar um objeto todo no NSUserDefaults você deve implementar os métodos que vão serializar e deserializar os dados...
// NSPessoa.h --------------------------------
#import 

@interface NSPessoa : NSObject

@property (nonatomic, strong) NSString *nome;
@property (nonatomic, strong) NSString *email;

@end

// NSPessoa.m --------------------------------
#import "NSPessoa.h"

@implementation NSPessoa

@synthesize nome, email;

- (void)encodeWithCoder:(NSCoder *)encoder {
  [encoder encodeObject:self.nome  forKey:@"nome"];
  [encoder encodeObject:self.email forKey:@"email"];
}

- (id)initWithCoder:(NSCoder *)decoder {
  if((self = [super init])) {
    self.nome  = [decoder decodeObjectForKey:@"nome"];
    self.email = [decoder decodeObjectForKey:@"email"];
  }
  return self;
}
@end

Abaixo o código para carregar e salvar os dados.
// Carregando ----------------------------------
NSUserDefaults *prefs = 
  [NSUserDefaults standardUserDefaults];

NSData *data = [prefs objectForKey:@"pessoa"];
NSPessoa *pessoa = (NSPessoa *)
  [NSKeyedUnarchiver unarchiveObjectWithData: data];

// se os dados da pessoa não existirem, 
// inicia um novo objeto    
if (!pessoa){
  pessoa = [NSPessoa new];
}

// Salvando ------------------------------------
NSData *data = [NSKeyedArchiver 
  archivedDataWithRootObject:pessoa];

NSUserDefaults *defaults = 
  [NSUserDefaults standardUserDefaults];

[defaults setObject:data forKey:@"pessoa"];

Qualquer dúvida, deixem seus comentários.

4br4ç05,
nglauber

domingo, 25 de outubro de 2009

Intents nativas do Android

Olá povo,

Um grande benefício que a plataforma Android trouxe para nós desenvolvedores foi a capacidade de nos comunicar com aplicações "nativas" através de intenções (Intents).
Sendo assim, resolvi publicar algumas das intents nativas mais comuns do Android. Segue abaixo o código-fonte.


public class ExemploIntents extends ListActivity {

private static final String[] OPCOES = {
"Browser",
"Realizando uma chamada",
"Visualizar contato",
"Todos os contatos",
"Mapa",
"Tocar música",
"SMS",
"Sair"
};

@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
ArrayAdapter<String> adapter =
new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1,
OPCOES);

setListAdapter(adapter);
}

@Override
protected void onListItemClick(ListView l, View v,
int position, long id) {

super.onListItemClick(l, v, position, id);
Uri uri = null;
Intent intent = null;

switch (position) {
// Abrindo uma URL
case 0:
uri = Uri.parse("http://nglauber.blogspot.com");
intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
break;

// Realiza uma chamada
case 1:
uri = Uri.parse("tel:99887766");
intent = new Intent(Intent.ACTION_DIAL, uri);
startActivity(intent);
break;

// Visualiza um contato específico
// da lista de contatos
case 2:
uri = Uri.parse(
"content://contacts/people/5");
intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
break;

// Visualiza todos os contatos e permite
// selecionar um através do resultado
// da Activity
case 3:
uri = Uri.parse(
"content://contacts/people/");
intent = new Intent(Intent.ACTION_PICK, uri);
startActivityForResult(intent, 0);
break;

// Pesquisa uma posição do mapa
// !Seu AVD deve estar usando Google APIs!
case 4:
uri = Uri.parse(
"geo:0,0?q=Rua+Amelia,Recife");
intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
break;

// Executa uma música do SDcard
case 5:
uri = Uri.parse(
"file:///sdcard/musica.mp3");
intent = new Intent();
intent.setDataAndType(uri,"audio/mp3");
startActivity(intent);
break;

// Abrindo o editor de SMS
case 6:
uri = Uri.parse("sms:12345");
intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra("sms_body", "Corpo do SMS");
startActivity(intent);
break;

default:
finish();
}
}

@Override
protected void onActivityResult(int requestCode,
int resultCode, Intent data) {

super.onActivityResult(requestCode,
resultCode, data);

// Mostra um contato selecionado (case 3)
// em um Toast
if (data == null){
Toast.makeText(this, "Nenhum contato",
Toast.LENGTH_SHORT).show();
} else {
Uri uri = data.getData();
Toast.makeText(this, "Contato: "+ uri,
Toast.LENGTH_SHORT).show();
}
}
}


Vamos explicar o que foi feito acima. Criamos uma lista com várias opções de intents nativas. E quando o usuário clicar em qualquer uma dessas opções, a respectiva Intent será disparada.
Em todos os casos, utilizamos o objeto Uri para criar a Intent. Esse objeto indica um recurso do aparelho queremos acessar, e baseado no protocolo informado, ele irá disparar a atividade desejada.
Em conjunto com a Uri, associamos uma ação que queremos realizar sobre o recurso. Vamos exemplificar como o Android entende a solicitação, usando o caso do Browser: "O usuário está com a intenção (Intent) de visualizar (ACTION_VIEW) o recurso (Uri) http://nglauber.blogspot.com". Nesse momento o Android faz uma busca interna pra saber quem pode tratar essa intenção.

No exemplo de discar um número, utilizamos a ação ACTION_DIAL e o protocolo "tel:" seguido do número do telefone a ser discado. Notem que aqui há uma diferença entre "discar" (ACTION_DIAL) e "chamar" (ACTION_CALL). A primeira opção apenas disca o número não chama. Se quiséssemos chamar o número ao invés de apenas discá-lo, deveríamos utilizar a ACTION_CALL e adicionar a permissão abaixo no manifest:

<uses-permission name="android.permission.CALL_PHONE"/>

Na lista de contatos temos dois casos. O primeiro visualiza um contato utilizando o protocolo "content://" - que identifica um ContentProvider - passando o caminho do provider de contatos. Já o segundo caso está usando a ação ACTION_PICK para recuperar a Uri de um contato específico. Para tal, é utilizado o método startActivityForResult que iniciará a tela de contatos permitindo que selecionemos um da lista. Para tratar o retorno da atividade, utilizamos o método onActivityResult.
Para abrir a aplicação de Mapas em um local específico utilizamos o protocolo "geo:" seguido do do endereço do local desejado. É possível passar também a longitude e latitude (geo:lat,long).
Para executarmos o MP3 Player padrão do aparelho passando uma música, utilizamos o método setDataAndType e passamos a Uri com o protocolo "file://" e informando o MIME type do arquivo.
Mais informações aqui.

4br4ç05,
nglauber