jun 09

Hoy venimos con otro artículo donde explicaremos la manera más simple de envíar emails desde nuestras aplicaciones.

A partir de la versión 3.0 del iPhone OS Apple introdujo un nuevo framework llamado MessageUI para permitir a los desarrolladores envíar emails desde sus aplicaciones de forma fácil y cómoda.

¿Cómo usarlo?

Antes que nada tenemos que incluir el MessageUI framework ya que no viene por defecto.

Una vez incluida el framework, en los ficheros donde vayamos a usar la funcionalidad de email tenemos que incluir las interfaces del framework con:

#import <MessageUI/MessageUI.h>

MessageUI framework nos ofrece una clase llamada MFMailComposeViewController que nos ofrece toda la funcionalidad de email de forma fácil y incluye la interfaz de usuario para edición de emails.

Aquí tenemos un ejemplo de uso (suponemos que estamos en un view controller):

//Creamos el controller encargado de los mails
MFMailComposeViewController *m = [[MFMailComposeViewController alloc] init];
//Asignamos los destinos a los que envíar el email
[m setToRecipients:[NSArray arrayWithObject:@"info@intelligentconta.com"]];
m.mailComposeDelegate = self;
//Mostramos la vista de edición de email
[self presentModalViewController:m animated:YES];
[m release];

En el código de arriba una de las partes a detectar es la asignación del delegado y es que en nuestro código donde vayamos a usar el MFMailComposeViewController tenemos que implementar el delegado MFMailComposeViewControllerDelegate para saber si el usuario ha enviado el email, si lo ha cancelado, si ha habido algun error, etc.
El delegado sólo contiene un método:
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
El parámetro MFMailComposeResult nos indicará el resultado con el que ha terminado la composición del email. Se suele usar este método para dependiendo del resultado esconder la vista de edición de email o mostrar un mensaje de error al usuario.

MFMailComposeViewController tiene otras propiedades y métodos para asignar ficheros adjuntos, destinatarios ocultos, etc. Puede consultar la documentación completa aquí.

VN:F [1.9.8_1114]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.8_1114]
Rating: 0 (from 0 votes)
Tagged with:
jun 09

En este artículo vamos a ver la forma más simple de reproducir vídeo en nuestras aplicaciones desde el código objecitve-c.

Para eso vamos a usar el MediaPlayer framework del iPhone. Al final del artículo podéis encontrar el link de descarga del poryecto de ejemplo.

Antes de empezar con la programación tenemos que añadir el framework MediaPlayer al nuestro proyecto ya que no viene por defecto. Como siempre, hacemos click derecho en el grupo Frameworks del proyecto y elegimos: Add > Exisiting Frameworks…

Esto nos abré la siguiente ventana donde tenemos que elegir el MediaPlayer y hacer click en Add:

Supongamos que tenemos un view controller que contiene un botón normal y queremos reproducir un vídeo al puslar en ese botón. También vamos a suponer que ya ha añadido ese botón en el Interface Bulider y lo ha enlazado con el método -(IBAction)playVideo:(id)sender de su view controller.

Vamos a ver el código a usar para crear el reproductor de vídeo que reproducirá un ficher de video determinado.

Antes que nada vamos a ver cómo sería la declaración de nuestra clase (el .h del view controller). Fíjense que hacemos #import <MediaPlayer/MediaPlayer.h> para poder acceder a las interfaces del MediaPlayer framework y declaramos una variable de tipo MPMoviePlayerController que se encargará de mostrar el vídeo.

#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
 
@interface EjemploVideoViewController : UIViewController {
	MPMoviePlayerController *player;
}
 
-(IBAction)playVideo:(id)sender;
 
@end

Ahora en el método – (void)viewDidLoad de nuestro view controller (en el .m) ponemos el siguiente código:

NSURL *movieFile = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"video" ofType:@"mp4"]];
player = [[MPMoviePlayerController alloc] initWithContentURL:movieFile];

En la primera línea obtenemos el path de nuestro fichero de vídeo (en este caso tenemos el vídeo entre nuestros ficheros de recursos como video.mp4) y con ese path creamos el reproductor del vídeo.

Finalmente al pulsar el botón que habíamos creado en el Interface Builder ejecutaremos el siguiente código:

[player play]

Y ya está, con esto conseguiremos reproducir un vídeo en nuestro programa.

Se puede usar el MPMoviePlayerController también para reproducir videos en streaming.
Los vídeos suelen ser ficheros grandes cuya carga puede llevar un tiempo determinado. Para el constructor de MPMoviePlayerController carga el vídeo en un thread diferente para no bloquear la ejecución del programa.
Si queremos saber cuando ha terminado la carga del vídeo podemos suscribirnos a la notificación llamada MPMoviePlayerContentPreloadDidFinishNotification de la siguiente manera:

[[NSNotificationCenter defaultCenter]
     addObserver:self
            selector:@selector(miMetodo:)
                name:MPMoviePlayerContentPreloadDidFinishNotification
               object:nil];

Descargar proyecto de ejemplo.

VN:F [1.9.8_1114]
Rating: 5.0/5 (1 vote cast)
VN:F [1.9.8_1114]
Rating: +1 (from 3 votes)
Tagged with:
jun 07

En muchísimas ocasiones en nuestros proyectos necesitamos cambiar el tamaño de las imágenes con las que trabajamos.

Hoy vamos a ver un segmento de código que podemos usar para no sólo cambiar el tamaño de nuestras imágenes sino también recortarlos.

En la app de Photos de iPhone en la vista donde se ve el mosáico de nuestros fotos podemos ver que las imágenes están escaladas para que quepan en un cuadradito y todos tengan el mismo tamaño. Para eso lo que hacen es escalar los imágenes y recortarlos.

A continuación vamos a ver un método que nos permite hacer lo de arriba citado.

El método recibe un UIImage y el tamaño final que queremos que tenga y devuelve un UIImage nuevo con el tamaño especificado:

- (UIImage*)imageWithImage:(UIImage*)image
			  scaledToSize:(CGSize)targetSize;
 
{
	UIImage *sourceImage = image;
	UIImage *newImage = nil;
	CGSize imageSize = sourceImage.size;
	CGFloat width = imageSize.width;
	CGFloat height = imageSize.height;
	CGFloat targetWidth = targetSize.width;
	CGFloat targetHeight = targetSize.height;
	CGFloat scaleFactor = 0.0;
	CGFloat scaledWidth = targetWidth;
	CGFloat scaledHeight = targetHeight;
	CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
 
	if (CGSizeEqualToSize(imageSize, targetSize) == NO)
	{
        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;
 
        if (widthFactor &gt; heightFactor)
			scaleFactor = widthFactor; // scale to fit height
        else
			scaleFactor = heightFactor; // scale to fit width
        scaledWidth  = width * scaleFactor;
        scaledHeight = height * scaleFactor;
 
        // center the image
        if (widthFactor &gt; heightFactor)
		{
			thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
		}
        else
			if (widthFactor &lt; heightFactor)
			{
				thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
			}
	}       
 
	UIGraphicsBeginImageContext(targetSize); // this will crop
 
	CGRect thumbnailRect = CGRectZero;
	thumbnailRect.origin = thumbnailPoint;
	thumbnailRect.size.width  = scaledWidth;
	thumbnailRect.size.height = scaledHeight;
 
	[sourceImage drawInRect:thumbnailRect];
 
	newImage = UIGraphicsGetImageFromCurrentImageContext();
	if(newImage == nil)
        NSLog(@"could not scale image");
 
	//pop the context to get back to the default
	UIGraphicsEndImageContext();
	return newImage;
}

Otra posibilidad tal vez más universal para recortar y cambiar el tamaño de los UIImages es hacer que los UIImage mismos lo soporten.
Eso se consigue implementando “Categories” para la clase UIImage.
En esta entrada(inglés) tenéis una buena implementación que dota de soporte a cambio de tamaño y recortado a los UIImages.

Código obtenido vía una entrada en StackOverflow

VN:F [1.9.8_1114]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.8_1114]
Rating: 0 (from 0 votes)
Tagged with:
jun 05

Hoy vamos a ver como se pueden crear vistas (UIViews) personalizados.
En muchas ocasiones no tenemos suficiente con los controles que vienen con el UIKit y entonces tenemos que crear nuestros propios controles.
En este artículo vamos a ver un ejemplo muy simple de creación de vistas propias.
Al final del artículo podréis descargar el proyecto de ejemplo donde implementamos nuestra vista personalizada y hacemos uso de ella.
En el ejemplo vamos a intentar crear una barra de progreso simple.
Entonces, vamos a crear una nueva clase que heredará de UIView, la llamaremos “VistaPorcentaje”. Nuestra VistaPorcentaje tendrá dos propiedades: el porcentaje y el color de la barra.
Así queda la declaración de la clase:

#import 
 
@interface VistaPorcentaje : UIView {
	UIColor *barColor;
	CGFloat porcentaje;
}
 
@property (nonatomic, retain)UIColor *barColor;
@property (nonatomic, setter=setPorcentaje)CGFloat porcentaje;
 
-(void)setPorcentaje:(CGFloat)p;
 
@end

Ahora que ya tenemos definida nuestra clase vamos a ver su implementación:

#import "VistaPorcentaje.h"
 
@implementation VistaPorcentaje
@synthesize barColor, porcentaje;
 
- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
		self.barColor = [UIColor greenColor];
		self.porcentaje = 0.0;
 
    }
    return self;
}
 
- (void)drawRect:(CGRect)rect {
   CGContextRef context = UIGraphicsGetCurrentContext();
    context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, self.barColor.CGColor);
 
	//Calculamos el ancho de la barra dependiendo del porcentaje
	CGFloat ancho = self.frame.size.width * porcentaje/100.0;
 
	//Dibujamos la barra del porcentaje
	CGRect r = CGRectMake(0, 0, ancho, self.frame.size.height);
	CGContextAddRect(context, r);
    CGContextFillRect(context, r);
 
}
 
-(void)setPorcentaje:(CGFloat)p{
	porcentaje = p;
	if (porcentaje &gt; 100.0)
		porcentaje = 100.0;
 
	if (porcentaje &lt; 0.0)
		porcentaje = 0.0;
 
	[self setNeedsDisplay];
}
 
- (void)dealloc {
	[barColor release];
	[super dealloc];
}
@end

Aquí los métodos claves son el drawRect y setPorcentaje. Dentro de drawRect implementamos toda la funcionalidad de pintura de nuestra vista. Básciamente en nuestro caso sólo pintamos un rectangulo de un tamaño equivalente al porcentaje respecto al ancho total de la vista.
Y el otro método, setPorcentaje, se llama cada vez que el usuario cambia la propiedad porcentaje. Fijaros que en este método tenemos una llamada [self setNeedsDisplay]. Con esa llamada decismos que se repinte (nunca llamamos directamente a drawRect) ya que se ha cambiado el porcentaje.

A continuación podemos ver un ejemplo de nuestro control (estamos en un view controller):

- (void)viewDidLoad {
    [super viewDidLoad];
 
	VistaPorcentaje *v = [[VistaPorcentaje alloc] initWithFrame:CGRectMake(10, 10, 200, 50)];
	v.backgroundColor = [UIColor whiteColor];
	v.barColor = [UIColor greenColor];
	v.porcentaje = 67.0;
	[self.view addSubview:v];
	[v release];
 
}

A base de este simple ejemplo se puede construir controles propios para mostrar histogramas, crear controles propios que respondan a las acciones de usuario y miles de cosas más.

EjemploVistaPersonalizada

VN:F [1.9.8_1114]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.8_1114]
Rating: 0 (from 0 votes)
Tagged with:
jun 05

Cuando queremos crear una aplicación que contenga diferentes funcionalidades relacionadas con el uso de la aplicación, pero independientes entre si, como mostrar los datos de diferente manera o diferentes tareas, querremos usar una Tab Bar en nuestra aplicación.

La Tab Bar nos dará acceso a esas diferentes tareas o vistas, separándolas dentro de nuestra aplicación como módulos independientes, además, sitúa al usuario dentro de la aplicación indicándole lo que esta viendo en ese momento.

Hoy daremos las indicaciones básicas para crear y configurar una Tab Bar para nuestra aplicación. Dentro de Xcode tenemos una plantilla que nos crea una aplicación con un Tab Bar y dos vistas diferentes, aunque es un buen punto de partida, cuando miramos el código a penas vemos que es lo que realmente se esta haciendo ya que toda la configuración la hacen desde Interface Builder. Nosotros mostraremos algo más de código.

Estructura

Tenemos nuestra aplicación, dentro de ésta estará nuestra Tab Bar, a la que le indicaremos que vistas (UIViewController) ha de mostrar, cada vista se ocupará de su funcionalidad, pero tenemos que configurar la propiedad tabBarItem (UITabBarItem), de cada una de las vistas para que la Tab Bar nos pueda mostrar el icono y titulo de esa pestaña.

Datos

Para configurar la Tab Bar lo único que necesitamos es un icono para cada pestaña, y un título. Podemos usar ambos a la vez o cada uno por separado, obviamente una Tab Bar sin iconos pierde mucho, por lo que recomiendo que al menos se use un icono para representar lo que la pestaña hace, el título siempre va bien por si el icono no deja del todo claro.

El titulo no es más que una cadena que indicaremos dentro del código, pero el icono es algo más especial y aunque Apple nos suministra algunos iconos típicos del sistema, para usarlos echar un vistazo a  UITabBarSystemItem, también nos indica como tenemos que crear nuestros propios iconos:

▪ Usar formato PNG.
▪ El único color a de ser blanco puro con transparencia apropiada.
▪ No añadir sombras.
▪ Usar anti-aliasing.
▪ Tamaño de 30 x 30 pixeles.

Código

Para crear la Tab Bar y añadirla a nuestra aplicación simplemente usar lo siguiente:

- (void)applicationDidFinishLaunching:(UIApplication *)application {
 
tabBarController = [[UITabBarController alloc] init];
 
MyViewController* vc1 = [[MyViewController alloc] init];
 
MyOtherViewController* vc2 = [[MyOtherViewController alloc] init];
 
NSArray* controllers = [NSArray arrayWithObjects:vc1, vc2, nil];
 
tabBarController.viewControllers = controllers;
 
[window addSubview:tabBarController.view];
 
}

En el applicationDidFinishLaunching creamos el TabBarController, los UIViewController para cada una de nuestras pestañas, metemos estos últimos en un vector y le indicamos al controlador de la Tab Bar que serán esos los que ha de mostrar. Finalmente añadimos la vista de la Tab Bar a nuestra ventana y listos.

Para configurar cada uno de los UITabBarItem de cada una de las vistas podemos usar las siguientes líneas:

UIImage* anImage = [UIImage imageNamed:@"MyTabBarIcon.png"];
 
UITabBarItem* theItem = [[UITabBarItem alloc] initWithTitle:@"TabBarItemTitle" 
                                                     image:anImage tag:0];
 
[myViewController setTabBarItem:theItem];

Normalmente se usarán dentro del mismo controlador, al inicializarlo, pero puede ser necesario hacerlo desde otro lugar cuando no estamos creando nuestra propia clase, por ejemplo si una de las vistas usa un UINavigationBar, en ese caso se puede usar el código anterior justo cuando creamos el controlador para la barra de navegación.

VN:F [1.9.8_1114]
Rating: 5.0/5 (1 vote cast)
VN:F [1.9.8_1114]
Rating: -1 (from 1 vote)
Tagged with:
may 29

Esta misma semana, en un post anterior, se enseñaba como usar la típica animación para mostrar una vista con los créditos del programa usando animaciones. Hoy vamos a hacer lo mismo pero usando la presentación de vistas modales que ya viene implementada en la clase UIViewController.

Lo que se mostró en el post anterior nos va bien cuando queremos controlar completamente la animación, pero esta otra forma nos ahorra mucho código y si no queremos hacer nada especial, durante la animación, es suficiente.

Empezamos de igual forma, tenemos una vista de tabla dentro de una barra de navegación, añadimos el boton de información en nuestro controlador de la vista principal.

- (void)viewDidLoad {
    [super viewDidLoad];
 
    self.title = @"Menu inicial";
 
    UIButton* infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
    [infoButton addTarget:self action:@selector(showAbout:) forControlEvents:UIControlEventTouchUpInside];
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:infoButton];
}

Pero en este caso nuestro showAbout será más sencillo

-(void)showAbout:(id)sender{
	AboutController *a = [[AboutController alloc] init];
	UINavigationController *n = [[UINavigationController alloc] initWithRootViewController:a] ;
	[a release];
 
	[a setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
	[self presentModalViewController:n animated:YES];
}

Seguimos creando una barra de navegación y nuestra vista de creditos, pero esta vez le indicamos a nuestra vista de creditos como queremos que sea la animación al presentarla, en modo modal, mediante [a setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal]; y finalmente le indicamos al controlador de la vista en la que estamos, que nos presente la vista de la nueva barra de navegación.

Aquí hay un punto un poco confuso, le estamos indicando a un controlador como ha de ser la animación, pero presentando otro controlador diferente, de echo, si en lugar de [a setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal]; usamos [n setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal]; con el controlador de la barra de navegación, obtenemos el mismo resultado, ya que la vista de creditos es el rootViewController de ésta. Pero no podemos hacer lo mismo con la última instrucción, porque entonces no se mostraría la barra de navegación que nos permite cerrar la vista de créditos.

Ahora en el .m de About controller dejamos el viewDidLoad intacto, añadimos el botón “Ok” y hacemos que al pulsarlo se vuelva a nuestro controller principal.

- (void)viewDidLoad {
    [super viewDidLoad];
    UIBarButtonItem *btn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemDone target:self action:@selector(close:)];
    self.navigationItem.rightBarButtonItem = btn;
    [btn release];
}
 
pero nuestro close se reduce a una única llamada que hace la animación contraria y nos devuelve a la vista principal
 
-(void)close:(id)sender{
       [self dismissModalViewControllerAnimated:YES];
}

Fijaros también que, de esta manera, no nos hace falta guardar el controlador principal en una variable para volver a él, ya que de esta forma lo seguimos teniendo en la jerarquia de vistas.

VN:F [1.9.8_1114]
Rating: 5.0/5 (1 vote cast)
VN:F [1.9.8_1114]
Rating: +1 (from 1 vote)
Tagged with:
may 23

Muchos programas suelen tener el típico botón de información que al pulsarlo abre la pantalla de información del programa con una animación de rotación.
En este artículo vamos a ver como se puede hacer eso si tenemos un navigation bar y queremos que rote toda la vista.
Al final del artículo están disponibles para la descarga los ficheros del proyecto de ejemplo.

En el siguiente vídeo podéis ver el efecto que queremos conseguir:

Vamos a suponer que tenemos una app donde la primera vista es un tableview que se encuentra envuelto en un navigation bar.

Y queremos poner el botón de información en el navigation bar. Para eso escribiremos este código en el viewDidLoad del nuestro view controller principal:

- (void)viewDidLoad {
    [super viewDidLoad];
 
    self.title = @"Menu Inicial";
 
    UIButton* infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
    [infoButton addTarget:self action:@selector(showAbout:) forControlEvents:UIControlEventTouchUpInside];
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:infoButton];
}

Y al pulsar el botón de información se ejecutará el siguiente método:

-(void)showAbout:(id)sender{
	AboutController *a = [[AboutController alloc] init];
 
	UINavigationController *n = [[UINavigationController alloc] initWithRootViewController:a] ;
	a.rc = self;
	[a release];
 
	UIView *s = self.navigationController.view.superview;
	[UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:0.75];
        [UIView setAnimationDelegate:self];
	[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:s cache:YES];
	    [self.navigationController.view removeFromSuperview];
	    [s addSubview:n.view];
	[UIView commitAnimations];
}

Lo importante del código de arriba es ver que creamos el AboutController que se encarga de la vista de “Acerca de” y lo ponemos en un navigation bar.
También es interesante ver el bloque de animación. Las animaciones empiezan con beginAnimation y terminan con commitAnimations. Son como las llaves de un método. Todo lo que queda entre esas dos llamados tiene que ver con la animación. Arriba de todo configuramos la animación (la duración, el tipo de la animación, respecto a que vista se hace la animación, etc.) y después indicamos que se hace durante la animación. En este caso decimos que se quite la vista actual y se ponga la vista de nuestro “About”.
Otra cosa que puede parecer raro es la sentencia: a.rc = self;. Con esto pasamos la referencia del controller actual al controller de about para que about tenga una referencia hacia el controller actual y pueda volver ese controller.
En el .h de nuestro about controller tenemos lo siguiente (fijaros en la referencia rc):

#import
#import "RootViewController.h"
 
@interface AboutController : UIViewController {
	RootViewController *rc;
}
 
@property (nonatomic, assign)RootViewController *rc;
-(void)close:(id)sender;
 
@end

Y en el .m de About controller añadimos el botón “Ok” y hacemos que al pulsarlo se vuelva a nuestro controller principal.

- (void)viewDidLoad {
    [super viewDidLoad];
	UIBarButtonItem *btn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemDone target:self action:@selector(close:)];
	self.navigationItem.rightBarButtonItem = btn;
	[btn release];
}
 
-(void)close:(id)sender{
 
	UIView *s = self.navigationController.view.superview;
	[UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:0.75];
        [UIView setAnimationDelegate:self];
        [UIView setAnimationDidStopSelector:@selector(transitionDidStop:finished:context:)];
	[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:s cache:YES];
 
	[self.navigationController.view removeFromSuperview];
	[s addSubview:rc.navigationController.view];
 
	[UIView commitAnimations];	
 
	[self.navigationController release];
}

Y con esto cerramos el artículo. Si tenéis preguntas no dudeis en formularlos usando el sistema de comentarios.
Descargar código de ejemplo de animacion

VN:F [1.9.8_1114]
Rating: 5.0/5 (1 vote cast)
VN:F [1.9.8_1114]
Rating: +1 (from 1 vote)
Tagged with:
may 23

Hoy veremos un ejemplo muy sencillo de cómo usar y para que sirve el protocolo NSKeyValueOnserving (KVO), al igual que en otros posts, lo que aquí se explica se puede usar en muchos otros casos.

Este protocolo nos sirve para detectar cambios en los valores de atributos de objetos y funciona de la siguiente manera:

  • Tenemos un objeto X del que queremos saber cuando un atributo se modifica
  • Tenemos un objeto Y que ha de realizar una acción cuando X modifica su atributo
  • El protocolo anterior nos permite que el objeto Y sea avisado de los cambios para el atributo que especifiquemos del objeto X.

Para conseguir esto sólo tenemos que indicarle a X que Y quiere ser avisado de dichos cambios usando el método addObserver:forKeyPath:options:context: definido en el protocolo y realizar las acciones oportunas usando el método observeValueForKeyPath:ofObject:change:context: en el objeto Y, ya que este es el mensaje que se le envía cuando dicho atributo cambia su valor.

Cómo ejemplo usaremos ese método para detectar cuando un usuario selecciona o deselecciona una anotación (MKAnnotation) en un mapa (MKMapView). Primero indicaré como montar el proyecto a modo de tutorial y más abajo como se usa exactamente el KVO, si ya teneis vuestro proyecto montado pasad directamente a la segunda sección.

Preparación

Primero creamos un nuevo proyecto usando la plantilla de Xcode basado en una vista. Añadimos al proyecto el Framework MapKit para poder usar el mapa y las anotaciones.
Luego modificamos el controlador de la vista para añadirle un IBoutlet que nos referencia al mapa que más adelante añadiremos. Tendremos que importar el Framework.

#import <UIKit/UIKit.h>;
#import <MapKit/MapKit.h>;
 
@interface MapKVOViewController : UIViewController  {
 
	IBOutlet MKMapView *theMapView;
}
 
@end

Abrimos con Interface Builder el archivo MapKVOViewController.xib y le añadimos un MKMapView que asignaremos al IBoutlet creado anteriormente, también indicaremos que el delegado del mapa será el propio controlador.
Para las anotaciones en el mapa necesitamos añadir otra clase a nuestro proyecto, con Xcode añadir una nueva clase a partir de un NSObject, importaremos aquí también el Framework MapKit. Esta clase ha de cumplir con el protocolo MKAnnotation así que modificamos el .h para que así sea.

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
 
@interface MapAnnotation : NSObject {
	NSString *title;
	NSString *subtitle;
	CLLocationCoordinate2D coordinate;
}
 
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
 
// Title and subtitle for use by selection UI.
- (NSString *)title;
- (NSString *)subtitle;
 
@end

Cómo esta clase no es más que para un test, inicializaremos las variables a valores constantes, modificar el .m para que se parezca a esto

@implementation MapAnnotation
 
@synthesize coordinate;
 
- (id)init {
	[super init];
 
	coordinate.latitude = 25;
	coordinate.longitude = 25;
	title = [NSString stringWithFormat:@"A Testing annotation"];
	[title retain];
	subtitle = [NSString stringWithFormat:@"selecting detection"];
	[subtitle retain];
	return self;
}
 
- (NSString *)title {
	return title;
}
 
- (NSString *)subtitle{
	return subtitle;
}
 
- (void)dealloc{
	[title release];
	[subtitle release];
	[super dealloc];
}
 
@end

Para acabar con la preparación del proyecto solo nos falta añadir una anotación en el mapa, por ejemplo usar el viewDidLoad para hacerlo. Acordaros de importar vuestra nueva clase para las anotaciones en el mapa (aquí MapAnnotation).

- (void)viewDidLoad {
    [super viewDidLoad];
	MapAnnotation *newAnnotation = [[MapAnnotation alloc] init];
	[theMapView addAnnotation:newAnnotation];
}

Uso de KVO

En nuestro ejemplo, el objeto X es la vista de la anotación, el pin que se ve en el mapa, es decir, tenemos por un lado la anotación en si y por otro una vista que la representa en el mapa, como la acción de seleccionar se realiza sobre el mapa, es la vista de la anotación, la que tiene un atributo llamado selected, que es el que querremos vigilar.

Por otro lado, el objeto Y, será nuestro MapKVOViewController, que es el encargado de añadir las anotaciones al mapa.

Primer paso, indicarle al objeto X que queremos observar el atributo selected, suponiendo que queramos hacer esto con todas las anotaciones del mapa, un buen sitio es el método mapView:didAddAnnotationViews: del protocolo MKMapViewDelegate, añadir este método a nuestro controlador y modificarlo para que sea como este

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
	for (MKAnnotationView *anAnnotationView in views) {
		[anAnnotationView setCanShowCallout:YES];
		[anAnnotationView addObserver:self
						 forKeyPath:@"selected"
					              options:NSKeyValueObservingOptionNew
						      context:ANNOTATION_SELECTED_DESELECTED];
	}
}

Tened en cuenta que esto se hará para cada anotación, por lo que, si tenéis diferentes tipos de anotaciones, tendréis que diferenciar entre cuales queréis observar y cuales no.

El método que nos interesa es addObserver:forKeyPath:options:context:, a éste le indicamos quien será el observador, self, que atributo queremos observar, selected, con que opciones, NSKeyValueObservingOptionNew indica que queremos el nuevo valor, y un contexto, que se usa para darnos mas información, por ejemplo qué estamos observando, aquí podéis usar nil si sólo observáis una cosa, en caso de que tengáis que diferenciar, es muy útil usar constantes para cada caso, aquí usamos

static NSString* const ANNOTATION_SELECTED_DESELECTED = @"mapAnnotationSelectedOrDeselected";

definida al principio de nuestro .m

Finalmente, para poder realizar cualquier acción, una vez notificados del cambio, tenemos que sobrescribir el método observeValueForKeyPath:ofObject:change:context:

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
 
    NSString *action = (NSString *)context;
	if ([action isEqualToString:ANNOTATION_SELECTED_DESELECTED]) {
		BOOL annotationSelected = [[change valueForKey:@"new"] boolValue];
		if (annotationSelected) {
			NSLog(@"Annotation was selected, do whatever required");
                        // Accions when annotation selected
		}else {
			NSLog(@"Annotation was deselected, do what you must");
                        // Accions when annotation deselected
		}
	}
}

Añadir el código para realizar la acción que queráis una vez sepáis si se ha seleccionado o deseleccionado la anotación, por ejemplo reproducir un sonido.

VN:F [1.9.8_1114]
Rating: 5.0/5 (4 votes cast)
VN:F [1.9.8_1114]
Rating: +3 (from 3 votes)
Tagged with:
may 16

Hoy explicaré como conseguir reproducir un sonido cuando se pulsa un botón, de hecho, lo que explicaré se puede usar para muchas más cosas y no sólo para botones, ya que lo que haré será crear un SystemSoundID que se usan, entre otras cosas, para reproducir sonidos cortos (30 segundos o menos). Pero como ejemplo, usaré un botón.

Para poder reproducir sonidos necesitaremos añadir el Framework AudioToolbox a nuestro proyecto.

Imaginaros que contamos con un UIViewController y la vista que éste controla, añadamos un UIButton a la vista mediante Interface Builder o a base de código, como más os guste. Si aun no hemos añadido el Framework a nuestro proyecto hacedlo ahora, una vez añadido tendremos que importarlo a nuestro controlador.

En el archivo cabecera (.h) de nuestro controlador añadimos una variable de tipo SystemSoundID, y un método que será llamado cuando se pulse el botón.

#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h>
 
@interface testKeyboardViewController : UIViewController <UITextFieldDelegate> {
 
	SystemSoundID buttonSoundID;
}
- (IBAction)buttonPressed;
 
@end

Ahora necesitamos un archivo de audio, con el sonido que queramos, por ejemplo ButtonSound.caf, y en el método viewDidLoad de nuestro controlador añadir las siguientes líneas para crear la referencia a nuestro sonido.

- (void)viewDidLoad {
    [super viewDidLoad];
	NSString *path = [[NSBundle mainBundle] pathForResource:@"ButtonSound" ofType:@"caf"];
	AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path], &buttonSoundID);	
}

Como veis en el código, necesitamos la ruta a nuestro archivo de audio, si habéis añadido el archivo a vuestro grupo Resources en Xcode, el código anterior debería funcionar. Echad un vistazo a NSBundle en caso de que no sea así para buscar otro método que os deje encontrar el archivo.

Con eso ya tenemos creada la referencia al sonido, ahora solo falta reproducir éste cuando sea necesario, en este ejemplo, queremos que se reproduzca cuando pulsamos el botón. Para ello tenemos que añadir una línea a la función que llamamos cuando se pulsa el botón.

- (IBAction)buttonPressed {	
	AudioServicesPlaySystemSound(buttonSoundID);
}

Con esto ya deberíais oír el sonido cuando pulsáis el botón.

En caso de no necesitar más el sonido en cuestión, podéis usar la siguiente función para eliminar la referencia creada, por ejemplo en el viewDidUnload de nuestro controlador.

- (void)viewDidUnload {
	AudioServicesDisposeSystemSoundID(buttonSoundID);
}

Espero que esto os sea útil para añdirle a vuestra aplicación todo tipo de sonidos cortos, para darle un poco más de vida.

VN:F [1.9.8_1114]
Rating: 5.0/5 (2 votes cast)
VN:F [1.9.8_1114]
Rating: +2 (from 2 votes)
Tagged with:
may 15

En muchas ocasiones nuestras aplicaciones están pesnados sólo para funcionar en el modo apaisanado (horziontal) del iPhone.

En muchos juegos es muy común que sólo funcionen en ese modo. Entonces que hemos de hacer para que nuestra aplicación sólo aparezca en ese modo?

Primero de todo tenemos que añadir el método shouldAutorotateToInterfaceOrientation en nuestro view controller. Generlmente el XCode lo añade automáticamente al crear el view controller, nosotros sólo tenemos que descomentarlo y añadir nuestro código.

La implementación del método debería quedar así:

- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)o {
        return UIInterfaceOrientationIsLandscaper(o);
}

Y finalmente debemos editar nuestro fichero .plist. Abrir el fichero haciendo click con el botón dereche y eligiendo: Open As > Plain Text File. Y en el fichero abierto añadiremos estás líneas:

    <key>UIInterfaceOrientation</key>
    <string>UIInterfaceOrientationLandscapeRight</string>
</dict>
</plist>

Con esto forzamos que la apicación siempre se inicie en el modo apaisanado.

VN:F [1.9.8_1114]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.8_1114]
Rating: +1 (from 1 vote)
Tagged with:
preload preload preload