Desarrollo de aplicaciones para dispositivos móviles: Programación para iOS Luis Montesano %RE'1YVMPPS Índice Aprovechando el hardware “específico”: Sensores del iPhone • Vistas web, mapas, localización • Multitouch • Giróscopo, • Cámara acelerómetro Sensores del iPhone Localización & vistas-web Cámara Acelerómetros, giroscopo Multi-touch Mostrar contenido web localización: CORE LOCATION “Servicio” para que la aplicación acceda a las estimaciones de localización localización: CORE LOCATION • Localización de 3 sensores: GPS + Wifi + Red de móviles. Cuanto más preciso más gasto de bateria. Se comprueban/complementan todos los posibles. • Clase básica: CLLocation! @property (readonly) CLLocationCoordinate2D coordinate; ! @property(readonly) CLLocationDistance altitude;! @property (readonly) CLLocationAccuracy horizontalAccuracy; // metros! @property (readonly) CLLocationAccuracy verticalAccuracy; // metros! (kCLLocationAccuracyBestForNavigation; kCLLocationAccuracyBest; kCLLocationAccuracyNearestTenMeters; kCLLocationAccuracyHundredMeters; kCLLocationAccuracyKilometer; kCLLocationAccuracyThreeKilometers;)! Y velocidad, orientación, timestamp,…! - (CLLocationDistance)distanceFromLocation:(CLLocation *)otherLocation; //metros! localización: CORE LOCATION Crear un CLLocationManager: alloc/init + configurar + arrancar • Comprobar que tenemos el hardware necesario. "@property BOOL headingAvailable; ! "@property BOOL locationServicesEnabled; • Crear CLLocationManager y establecer el “delegado”. "CLLocationManager *clm = [[CLLocationManager alloc] init];! "@property(assign, nonatomic) id <CLLocationManagerDelegate> delegate; • Configurar el manager "clm.distanceFilter=10.0; //minimum distance change to report,in meters "clm.desiredAccuracy = kCLLocationAccuracyTenMeters;! • Arrancar la monitorización de los cambios: Monitorización continua: "Monitorización [clm startUpdatingLocation];! de cambios “significativos”: - (void)startMonitoringSignificantLocationChanges;! "Monitorización por zonas: - (void)startMonitoringForRegion:(CLRegion "Monitorización de la orientación: - (void)startUpdatingHeading;! ! *) desiredAccuracy:(CLLocationAccuracy); localización: CORE LOCATION • El delegado del “manager recibira las notificaciones, por ejemplo:! - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *) newLocationfromLocation:(CLLocation *)oldLocation;! ! - (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading; • También se puede acceder directamente CLLocation *location = clm.location;! CLHeading *heading = clm.heading;! • Manejar errores/interferencias • Solicitar permiso al usuario para usar servicios de localización localización: CORE LOCATION Ejemplo Locations Sensores del iPhone Localización & vistas-web Cámara Acelerómetros, giroscopo Multi-touch Eventos Además de “manejadores” de eventos relacionados con las vistas y el programa (load, unload, appear, …) hay muchos otros tipos de eventos que podemos “gestionar” y capturar generados por los sensores. • Preprocesados : “shake”, gestureRecognizer (gestos típicos) y “Servicios” (localización, movimiento) • Datos “en crudo” (procesado personalizado de gestos o lecturas en crudo de los sensores) Eventos UIEvent : Eventos de (multi-)touch, de movimiento y del control-remoto .type typedef enum { UIEventTypeTouches, UIEventTypeMotion, UIEventTypeRemoteControl,} UIEventType; .subtype typedef enum { UIEventSubtypeNone UIEventSubtypeMotionShake UIEventSubtypeRemoteControlPlay UIEventSubtypeRemoteControlPause UIEventSubtypeRemoteControlStop UIEventSubtypeRemoteControlTogglePlayPause UIEventSubtypeRemoteControlNextTrack UIEventSubtypeRemoteControlPreviousTrack UIEventSubtypeRemoteControlBeginSeekingBackward UIEventSubtypeRemoteControlEndSeekingBackward UIEventSubtypeRemoteControlBeginSeekingForward UIEventSubtypeRemoteControlEndSeekingForward} UIEventSubtype; Eventos (multi)-touch • UIControlEvents (código o IB) (UIControl es la clase “base” para objetos de “control”: botones,…) Qué es cada evento? (ejemplo: ControlDemo) UIControlEventTouchDown UIControlEventTouchDownRepeat UIControlEventTouchDragInside UIControlEventTouchDragOutside UIControlEventTouchDragEnter UIControlEventTouchDragExit UIControlEventTouchUpInside UIControlEventTouchUpOutside UIControlEventTouchCancel Eventos (multi)-touch UITouch: representa un toque (un dedo sólo) @property(nonatomic,readonly) NSTimeInterval timestamp; fin) @property(nonatomic,readonly) UITouchPhase @property(nonatomic,readonly) NSUInteger phase; tapCount; @property(nonatomic,readonly,retain) UIWindow *window; @property(nonatomic,readonly,retain) UIView *view; - (CGPoint)locationInView:(UIView (inicio, moviendo, parado, *)view; - (CGPoint)previousLocationInView:(UIView *)view; UIEvent: contiene un conjunto de “toques” @property(nonatomic,readonly) NSTimeInterval timestamp; -(NSSet *)allTouches; -(NSSet *)touchesForWindow:(UIWindow *)window; -(NSSet *)touchesForView:(UIView *)view; UIResponder: interface para objetos que manejen eventos (super de UIApplication, UIView, UIWindow…) - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; Eventos (multi)-touch • Activar en UIView : property BOOL multipleTouchEnabled; Multiple-touch en una vista Touchs en varias vistas Eventos (multi)-touch • Las subclases de UIView y UIViewController deben manejar (implementar) todos los métodos relacionados con “touch” (y no se lo pasan al super), aunque sea null. - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; • Las demás subclases de elementos de UIKit pueden implementar los que se quiera, pero además deben pasar el evento al super [super touchesBegan:theTouches withEvent:theEvent]; Eventos (multi)-touch Ejemplo: MultiTouchDemo Eventos (multi)-touch Para los gestos típicos, más fácil! UIGestureRecognizer (abstract) subclasses de UIGestureRecognizer • • • • • • UITapGestureRecognizer UIPinchGestureRecognizer UIRotationGestureRecognizer UISwipeGestureRecognizer UIPanGestureRecognizer UILongPressGestureRecognizer Actua de”supervisor” cada vez que ocurre un UITouch en una vista: UIView: @property(nonatomic,copy) NSArray *gestureRecognizers Eventos (multi)-touch Los gestos tienen distintas propiedades y métodos para configurar y manejarlos. Algunos son: Todos tienen @property (readonly) UIGestureRecognizerState state; (Possible, Began, Changed, Ended, Cancelled, Failed, Recognized) UIPanGestureRecognizer – translationInView: – setTranslation:inView: – velocityInView: UIPinchGestureRecognizer @property CGFloat scale; @property (readonly) CGFloat velocity UIRotationGestureRecognizer @propertyCGFloatrotation @property (readonly) CGFloat velocity; UISwipeGestureRecognizer @property UISwipeGestureRecognizerDirection direction @property NSUInteger numberOfTouchesRequired; UITapGestureRecognizer @property NSUInteger numberOfTapsRequired; @property NSUInteger numberOfTouchesRequired; UILongPressGestureRecognizer @property(nonatomic) CFTimeInterval minimumPressDuration; Se pueden “programar” nuevos “gestureRecognizer” Eventos (multi)-touch Añadir gestureRecognizer a UIView desde un Controller - (void)viewDidLoad{ UIView*panView=...; //Vista del controlador donde queremos reconocer gestos UIGestureRecognizer *pangr = [[UIPanGestureRecognizer alloc] initWithTarget:panView action:@selector(pan:)]; [panView addGestureRecognizer:pangr]; [pangr release]; } Método del “target” para manejar el gesto • UIView: reconocer gestos • Cualquier objeto: pedir a UIView que reconozca gestos (mensaje “addGesture…”). • Normalmente UIView maneja los gestos reconocidos (no es obligatorio) Eventos (multi)-touch Definir como “procesar” el evento - (void)pan:(UIPanGestureRecognizer *)recognizer{ if ((sender.state == UIGestureRecognizerStateChanged) || (sender.state == UIGestureRecognizerStateEnded)) { CGPoint translation = [recognizer translationInView:self]; // mover algun elemento de la vista “afectada” (translation.x, translation.y) // e.g. si estamos en un grafico y el origen es una “property” origin } self.origin = CGPointMake(self.origin.x+translation.x, self.origin.y+translation.y) } [recognizer setTranslation:CGPointZero inView:self]; Eventos (multi)-touch Ejemplo Touches Eventos de movimiento Eventos de movimiento Datos “preprocesados” • Evento“agitar”: UIEvent type; @property(readonly) UIEventType @property(readonly) UIEventSubtype subtype;! UIEventTypeMotion • Para UIEventSubtypeMotionShake! “manejar” este evento: subclase de UIResponder que implemente - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {}! -(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event! -(void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event {}! Y además sea “first responder” - (BOOL)canBecomeFirstResponder {! return YES; !}! - (void)viewDidAppear:(BOOL)animated { ! [self becomeFirstResponder]; !} !! Eventos de movimiento Otros datos “preprocesados” de movimiento • La orientación de las pantallas: en la clase UIApplication: statusBarOrientation (interface, no device orientation) en la clase UIViewController: propiedad interfaceOrientation - (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation • La orientación “real” del dispositivo: clase UIDevice **! - Arrancar notificaciones: beginGeneratingDeviceOrientationNotifications Evento de cambio de orientación: UIDeviceOrientationDidChangeNotification (para “observadores registrados”) "[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];! "[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector "(orientationChanged:)name:UIDeviceOrientationDidChangeNotification object:nil]; ! ó acceder a propiedad orientation - Parar notificaciones: endGeneratingDeviceOrientationNotifications Eventos de movimiento clase UIDevice tambien proporciona: (Instancia única + currentDevice) • Opciones disponibles, versión, ID, OS … del dispositivo:!multitaskingSupported uniqueIdentifier name systemName systemVersion model • Estado de la batería: batteryLevel batteryMonitoringEnabled batteryState • Sensor de proximidad: proximityMonitoringEnabled proximityState! Eventos de movimiento Ejemplo: AlternateViews! “Control” de movimiento Para eventos de movimiento mas detallados: Core Motion: acelerómetro y giróscopo (sólo iPhone4 y iPod Touch nuevo). esto es mas “completo” (integra), antes se usaba UIAccelerometer class, CMMotionManager: - solo una instancia por aplicación pero es un recurso para “todos” - dos modos: samplear periódicamente la medición más reciente o suscribir un “manejador” para recibir todos los updates. (samplear más eficiente, mejor, salvo que “no se pueda perder ni una medida”) Control de movimiento (Core Motion) 1 – Comprobar disponibilidad del hardware @property (readonly) BOOL {accelerometer,gyro,deviceMotion}Available; 2 – Empezar la “captura” de datos. - (void)start{Accelerometer,Gyro,DeviceMotion}Updates; (SOLO si vamos a acceder a los datos) @property (readonly) BOOL {accelerometer,gyro,deviceMotion}Active; (comprobar si esta “en marcha”) 3 – “desconectar” la captura (cuanto antes!! ahorro de bateria) - (void)stop{Accelerometer,Gyro,DeviceMotion}Updates; Control de movimiento (Core Motion) Acceder a los datos “en crudo” @property (readonly) CMAccelerometerData *accelerometerData; Que contiene: @property (readonly) CMAcceleration acceleration;! typedef struct {double x;double y;double z;}CMAcceleration; ! (incluye gravedad) @property (readonly) CMGyroData *gyroData; Que contiene: @property (readonly) CMRotationRate rotationRate;! typedef struct { double x; double y; double z;} CMRotationRate;! (tiene un bias) @property (readonly) CMDeviceMotion *deviceMotion; (combinación de medida del gyro y acelerómetros) Control de movimiento (Core Motion) Acceder a los datos “filtrados” instanciando CMDeviceMotion Datos de aceleración @property (readonly) CMAcceleration gravity;! @property(readonly) CMAccelerationuser Acceleration; ! "//sin el “factor” gravedad gracias al giróscopo! typedef struct { double x; double y; double z; } CMAcceleration; // x, y, z in “g”! Datos de rotación @property CMRotationRate rotationRate; ! "//sin bias respecto a datos “crudos” gracias al acelerómetro! typedef struct {double x;double y;double z;} CMRotationRate;! @property CMAttitude *attitude; //orientación en 3D del dispositivo! Control de movimiento (Core Motion) Activar y samplear después (normalmente en bucle de aplicación) - (void)startAccelerometerUpdates;! @property NSTimeInterval accelerometerUpdateInterval; ! - (void)startGyroUpdates;! @property NSTimeInterval gyroUpdateInterval; ! - (void)startDeviceMotionUpdates;! @property NSTimeInterval deviceMotionUpdateInterval;! A partir de aquí, Core Motion actualiza la propiedad correspondiente del “UIMotionManager” con la medida más actual. Control de movimiento (Core Motion) Registrar “bloques” para recibir “updates” de las medidas (métodos del único CMMotionManager) - (void)startAccelerometerUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMAccelerometerHandler)handler;! - (void)startGyroUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMGyroHandler)handler;! - (void)startDeviceMotionUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMDeviceMotionHandler)handler;! Sensores del iPhone Localización & vistas-web Cámara Acelerómetros, giroscopo Multi-touch Acceso a la cámara • Clase UIImagePickerController (sin subclases, maneja interacciones con los UIViewController) • Protocolo UIImagePickerControllerDelegate (implementado por el delegado) • Configurar: ¿qué ocurre si se acepta la imagen o se cancela? ¿se puede editar antes de aceptar? • Comprobar disponibilidad de cámara: seleccionar imagen del dispositivo disponible (cámara o archivo). Acceso a la cámara Acceso a la cámara DEMO: añadir imagen desde archivo Acceso a la cámara Ejemplo: PhotoPicker Recordar … CUIDADO! con el gasto de batería: desconectar servicios en cuanto no se estén utilizando. Organización de módulos Core OS - OS X Kernel Mach 3.0 BSD - Sockets - Security - Power Mgmt - Keychain Certif. - File System - Bonjour Core Services - Collections - Address Book Media - Core Audio OpenAL - Audio Mixing - Networking - File Access - SQLite - Audio Recording - Video Playback - JPG, PNG, TIFF - PDF - Quartz (2D) - Core Animation - OpenGL ES - Core Location - Net Services - Threading prefs. - URL utilities Cocoa Touch - Multi-Touch Events and Controls - Core Motion - View Hierarchy - Localization - Alerts - Web View - Map Kit - Image Picker - Camera … Y Mañana … • Unos cuantos puntos más interesantes … Aplicaciones Diseño iPad y “universales” de aplicaciones accesibles Multi-task Almacenamiento • Repaso general • “Proyecto” permanente Repaso general • UICatalog • Mas ejemplos ?? Aplicaciones universales • Ejemplo … Aplicaciones accesibles • Ejemplo … Multi-task • This is a simple process: • Open your info.plist file • Add The Key UIApplicationExitsOnSuspend or Select Application does not run in background • Set the new key to YES or Fill in the tick box Almacenamiento permanente • Ejemplo