Aprendiendo Objetive-C para IOS (Dia 27)

Guion del blog de curso de Objetive-C para IOS – DIA 27
—————————————————————————–
Después de unos dias… volvemos a la carga con XCODE!!!
Vamos a ver esta vez, como crearnos una nueva vista, usando un scrollview, y metiendo una imagen, pero esta vez, queremos poder hacer zoom a la imagen, asi como arrastrar el dedo por la pantalla, y cambiar la ubicacion del archivo de imagen.

Voy a usar un mapa grande de la serie “Juego de Tronos”, que quiero utilizar proximamente en una aplicacion que tengo creada, y que estoy trabajando para actualizarla.
Creamos pues un nuevo proyecto de tipo single view como siempre, y creamos en la vista un UIScrollView
A continuacion, creamos una nueva clase, que sera una subclass de UIViewController, y la llamamos imagenViewController.
Por ultimo, vamos a las propiedades en el storyboard de nuestra vista, y le decimos que la clase es la de nuestro imagenViewController.
Hacemos el outlet de nuestro scrollView, y lo llamamos directamente scrollView
Importamos ahora la imagen del mapa, arrastrando el archivo de imagen a nuestro xcode. La llamaremos image1.jpg
Hasta aqui, solo hemos preparado nuestro proyecto. Vamos ahora con la programacion.
Hay que tener en cuenta, que tengo que arreglarmelas para que la imagen responda ante diferentes gestos del usuario, ya que queremos poder hacer zoom, o poder desplazar la imagen de un lado a otro.
Para eso, me creo una nueva clase que sera una subclase de UIImageView, a la que le daremos las diferentes caracteristicas para que responda ante los TAP del usuario. He usado un codigo de Apple, que esta en su pagina web, y lo he modificado un poquito para nuestros propositos. La clase se llamara TapDetectingImageView
Veamos como quedan los archivos de dicha clase (Fijaos en la explicacion de los comentarios
————-
TapDetectingImageView.h:
————————
@protocol TapDetectingImageViewDelegate;
@interface TapDetectingImageView : UIImageView {
    
    // Variables que agregamos a nuestra clase, para poder detectar los posibles toques.
    CGPoint tapLocation;         // Necesarios para guardar las cordenadas cuando se le da un toque a la pantalla
    BOOL multipleTouches;        // estara puesto a YES, si se le da mas de un toque
    BOOL twoFingerTapIsPossible; // Estara establecido a NO cuando se puedan usar dos toques.
    
}
@property (nonatomic, weak) id <TapDetectingImageViewDelegate> delegate;
@end
/*
 Vamos a definir ahora el protocolo necesario para que la aplicacion responda antes los toques del usuario.
 Implementaremos varios metodos, segun sea nuestro caso.
 */
@protocol TapDetectingImageViewDelegate <NSObject>
@optional
//En el caso de un simple toque
– (void)tapDetectingImageView:(TapDetectingImageView *)view gotSingleTapAtPoint:(CGPoint)tapPoint;
//En el caso de dos toques
– (void)tapDetectingImageView:(TapDetectingImageView *)view gotDoubleTapAtPoint:(CGPoint)tapPoint;
//En el caso de pellizcar la pantalla
– (void)tapDetectingImageView:(TapDetectingImageView *)view gotTwoFingerTapAtPoint:(CGPoint)tapPoint;
@end
————-
TapDetectingImageView.m:
————————
#import “TapDetectingImageView.h”
@implementation TapDetectingImageView
@synthesize delegate;
– (id)initWithImage:(UIImage *)image {
    self = [super initWithImage:image];
    if (self) {
        [self setUserInteractionEnabled:YES];
        
        UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
        UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
        UITapGestureRecognizer *twoFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerTap:)];
        
        [doubleTap setNumberOfTapsRequired:2];
        [twoFingerTap setNumberOfTouchesRequired:2];
        
        [self addGestureRecognizer:singleTap];
        [self addGestureRecognizer:doubleTap];
        [self addGestureRecognizer:twoFingerTap];
        
        //SI USAMOS ARC, tenemos que tapar estar lineas, sino las DESTAPAMOS
        //[singleTap release];
        //[doubleTap release];
        //[twoFingerTap release];
    }
    return self;
}
#pragma mark Private
– (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer {
    if ([delegate respondsToSelector:@selector(tapDetectingImageView:gotSingleTapAtPoint:)])
        [delegate tapDetectingImageView:self gotSingleTapAtPoint:[gestureRecognizer locationInView:self]];
}
– (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer {
    if ([delegate respondsToSelector:@selector(tapDetectingImageView:gotDoubleTapAtPoint:)])
        [delegate tapDetectingImageView:self gotDoubleTapAtPoint:[gestureRecognizer locationInView:self]];
}
    
– (void)handleTwoFingerTap:(UIGestureRecognizer *)gestureRecognizer {
    if ([delegate respondsToSelector:@selector(tapDetectingImageView:gotTwoFingerTapAtPoint:)])
        [delegate tapDetectingImageView:self gotTwoFingerTapAtPoint:[gestureRecognizer locationInView:self]];
}
    
@end
————-
Ya tenemos creado el archivo necesario para realizar la deteccion de los toques. Vamos ahora con nuestro archivo principal, llamado imageViewController.
————-
//
//  imagenViewController.h
//  Diario027
//
//  Created by david fraj blesa on 06/07/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
//Vemos que establecemos el protocolo UIScrollViewDelegate en la definicion, asi nos obligamos a implementar sus metodos si fuera necesarios
@interface imagenViewController : UIViewController<UIScrollViewDelegate>
//Conectamos el scrollview (Lo hemos realizado directamente, arrastrando con el raton hasta aqui)
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
//Creamos una variable de imagen
@property (retain, nonatomicUIImageView *image;
//Establecemos el metodo que cambiara el tamaño. Acordaos que esto es solo la definicion
– (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center ;
@end
————-
//
//  imagenViewController.m
//  Diario027
//
//  Created by david fraj blesa on 06/07/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import “imagenViewController.h”
//Debemos importar el archivo TapDetectingImageView.h, para poder usar los gestos
#import “TapDetectingImageView.h”  
//Definimos una CONSTANTE, para cambiar la velocidad del ZOOM
#define ZOOM_STEP 1.5
@implementation imagenViewController
//Hacemos el synthesize de scrollView(Nuestro scroll) y de image(nuestra imagen), para tener asi los getter y los setters.
@synthesize scrollView;
@synthesize image;
– (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}
– (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn’t have a superview.
    [super didReceiveMemoryWarning];
    
    // Release any cached data, images, etc that aren’t in use.
}
#pragma mark – View lifecycle
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
– (void)loadView
{
}
*/
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
– (void)viewDidLoad
{
    [super viewDidLoad];
}
*/
– (void)viewDidUnload
{
    //Cuando la vista de descargue, establecemos esto a nil
    [self setScrollView:nil];
    [self setImage:nil];
    
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}
– (void)viewDidLoad {  
    [super viewDidLoad];  
    
    //Cuando carguemos la VIEW, establecemos diferentes parametros de scrollView
    scrollView.bouncesZoom = YES;  
    scrollView.delegate = self;  
    scrollView.clipsToBounds = YES;  
    
    //Creamos la imagen, y le asignamos el mapa.
    image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@”image1.jpg”]];  
    image.userInteractionEnabled = YES;  
    image.autoresizingMask = ( UIViewAutoresizingFlexibleWidth );  
    
    //Añadimos dicha imagen a nuestro scrollView
    [scrollView addSubview:image];  
    
    //Establecemos el tamaño del contenido
    scrollView.contentSize = [image frame].size;  
    
    // añadimos el reconocedor de gestos a la imagen
    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];  
    UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];  
    UITapGestureRecognizer *twoFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerTap:)];  
    
    [doubleTap setNumberOfTapsRequired:2];  
    [twoFingerTap setNumberOfTouchesRequired:2];  
    
    [image addGestureRecognizer:singleTap];  
    [image addGestureRecognizer:doubleTap];  
    [image addGestureRecognizer:twoFingerTap];  
    
    //Si estamos usando ARC, tenemos que tener esto tapado, tal como esta aqui
    //[singleTap release];  
    //[doubleTap release];  
    //[twoFingerTap release];  
    
    // Calculamos la escala minima, para fijar la anchura de la imagen, y empezar a escalarla  
     float minimumScale=[scrollView frame].size.width/[image frame].size.width;
     
    //imageScrollView.maximumZoomScale = 1.0;  
    scrollView.minimumZoomScale = minimumScale;  
    scrollView.zoomScale = minimumScale;  
}  
– (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {  
    // Le ponemos return YES, para que soporte el cambio de orientacion 
    return YES;  
}  
#pragma mark UIScrollViewDelegate methods  
– (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {  
    return image;  
}  
#pragma mark TapDetectingImageViewDelegate methods  
//Que pasa si slo le damos una vez
– (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer {  
    // al darle solo una vez, no hacemos nada.  
}  
//Que pasa si le damos dos veces
– (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer {  
    // Hacemos zoom
    float newScale = [scrollView zoomScale] * ZOOM_STEP;  
    CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:gestureRecognizer.view]];  
    [scrollView zoomToRect:zoomRect animated:YES];  
}  
//Que pasa si pellizcamos
– (void)handleTwoFingerTap:(UIGestureRecognizer *)gestureRecognizer {  
    // Al pellizcar la pantalla 
    float newScale = [scrollView zoomScale] / ZOOM_STEP;  
    CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:gestureRecognizer.view]];  
    [scrollView zoomToRect:zoomRect animated:YES];  
}  
#pragma mark Utility methods  
//Metodo para reescalar
– (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center {  
    
    CGRect zoomRect;  
    
    //Como estamos recibiendo la nueva escala, la usamos para establecer el nuevo rectangulo, que hara el papel de zoom
    zoomRect.size.height = [scrollView frame].size.height / scale;  
    zoomRect.size.width  = [scrollView frame].size.width  / scale;  
    
    // Elegimos el origen correcto, que sera el centro de la pantalla 
    zoomRect.origin.x    = center.x – (zoomRect.size.width  / 2.0);  
    zoomRect.origin.y    = center.y – (zoomRect.size.height / 2.0);  
    
    return zoomRect;  
}  
@end
————-
He comentado todo el codigo para explicar lo que se hace en cada apartado.
Parte del codigo lo he recogido de esta pagina web
Lo malo que en esta web, esta todo en Ingles, y esta programado para la version anterior de XCODE, asi que he tenido que retocarlo un poco, para poder usar asi el ARC
Un saludo a todos!!
————-
nota: Esto es no es curso propiamente dicho, es un diario de autoaprendizaje de objetive-c, que me sirve para afianzar conocimientos, y de paso, tener un diario de referencia, con ejemplos propios de uso del lenguaje.
————-