Desarrollo de aplicaciones para dispositivos móviles: Programación para iOS Luis Montesano %RE'1YVMPPS Profesorado • Ana Cris Murillo Contacto: acm@unizar.es Profesora del Dpto. de Informática e Ing. de Sistemas, Universidad de Zaragoza. Investigación en visión por computador y robótica • Luis Montesano Contacto: montesano@unizar.es Profesor del Dpto. de Informática e Ing. de Sistemas, Universidad de Zaragoza. Investigación en aprendizaje y robótica Materiales, documentación, código ... • Información accesible en pdf y en web (Objective C, XCode, Cocoa, … ) Actualizaciones y complementos al material durante el curso • iPhone Dev center (http://developer.apple.com/iphone/index.action) • Curso programación iPhone Stanford (iTunes) Índice de este fin de semana • Repaso opciones diseño vistas básico - “hello world”? usando Xcode e IB. - ModelViewController. Vista simple. • Navegación: - Navigation controller, Tab Bar, Híbrido. - Construcción de ejemplo base para “proyecto de asignatura”. • Vistas - avanzadas: Tablas, Vistas Personalizadas “Hello World”: Objective C, Xcode, IB. MVC en una vista “simple” MVC en una vista “simple” • Patrón • Una • Un Model-View-Controller clase viewController sencillo Diseño de aplicaciones: opciones de navegación Control de navegación: “navigation controlers” Barra de navegación: Barra de “tabs”: UINavigationController UITabBarController Híbrido ... Vector de vistas: UITabBarController • Controlador de la vista seleccionada • Iconos/nombres de todos los controladores de vistas Vector de vistas: UITabBarController - (void)applicationDidFinishLaunching:(UIApplication *)application { ! tabBarController = [[UITabBarController alloc] init];! // Create a few view controllers! UIViewController *redViewController = [[UIViewController alloc] init];! redViewController.title = @"Red";! redViewController.tabBarItem.image = [UIImage imageNamed:@"faves.png"];! redViewController.view.backgroundColor = [UIColor redColor];! UIViewController *blueViewController = [[UIViewController alloc] init];! blueViewController.title = @"Blue";! blueViewController.tabBarItem.image = [UIImage imageNamed:@"search.png"];! blueViewController.view.backgroundColor = [UIColor blueColor];! MyViewController *myViewController = [[MyViewController alloc] initWithNibName:@"MyView" bundle:nil];! // Add them as children of the tab bar controller! tabBarController.viewControllers = ! [NSArray arrayWithObjects:redViewController, ! blueViewController, myViewController, nil];! // Don't forget memory management! [redViewController release];! [blueViewController release];! [myViewController release];! // Add the tab bar controller's view to the window! [window addSubview:tabBarController.view];! [window makeKeyAndVisible];! }! Vector de vistas: UITabBarController Si añadimos muchos elementos al vector, añade automaticamente botón de “more ...” para: • visualizar el resto y acceder • configurar el orden Vector de vistas: UITabBarController DEMO: MyTab Añadimos “vector” de “tabs” a la agenda-base (con uno de los tabs la vista “sencilla”) Pila de vistas: UINavigationController • Título del controlador de la vista encima de la pila. • Título del controlador de la vista anterior • Vista • Barra encima de la pila de herramientas de la vista encima de la pila Pila de vistas: UINavigationController • Personalizar barras de herramientas: UINavigationItem • Todos los controladores de vistas tienen un “navigationItem” para personalizar títulos, botones,... (opciones en UINavigationBar.h), se visualizan cuando ese controlador está en arriba de la pila: • Edit/done (muy común, pre-definido) self.navigationItem.leftBarButtonItem = self.editButtonItem; • Botones a izq. y dcha. : definir un botón y asignarlo como navigation item de la vista actual self.navigationItem.leftBarButtonItem = fooButton; self.navigationItem.rightBarButtonItem = addButton; • Cambiar • Botón el título por algún “control”: self.navigationItem.titleView = segmentedControl; de “volver”: por defecto escribe el título de la vista anterior. Se puede cambiar self.title = @“Hello there, CS193P!”; UIBarButtonItem *heyButton = [[UIBarButtonItem alloc] initWithTitle:@“Hey!” . . .]; self.navigationItem.backButtonItem = heyButton; Pila de vistas: UINavigationController en "MyAppDelegate.h"! #import "FirstViewController.h"! ...! - (void)applicationDidFinishLaunching:(UIApplication *)application {! // INICIALIZAR! navigationController = [[UINavigationController alloc] init];! [window addSubview:navigationController.view];! FirstViewController *viewController = ! [[FirstViewController alloc] ! initWithNibName:@"FirstView" bundle:nil];! [navigationController pushViewController:viewController ! animated:NO];! [viewController release];! // Override point for customization ! after application launch! [window makeKeyAndVisible];! }! Pila de vistas: UINavigationController En FirstViewController.m! - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {! if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {! // Custom initialization! self.title = @"¡Numero Uno!";! }! return self;! }! - (void)viewDidLoad {! [super viewDidLoad];! // AÑADIR BOTONES DE CONTROL! UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self ! action:@selector(add:)];! self.navigationItem.rightBarButtonItem = barButtonItem;! [barButtonItem release];! UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] ! initWithTitle:@"back" style:UIBarButtonItemStyleBordered target:nil ! action:nil];! self.navigationItem.backBarButtonItem = backBarButtonItem;! [backBarButtonItem release];! }! - (void)add:(id)sender! {! UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Nothing to add" message:@"Sorry, try again!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];! [alertView show];! [alertView release];! }! Pila de vistas: UINavigationController en FirstViewController.m! - (IBAction)push:(id)sender! {! SecondViewController *secondViewController = [[SecondViewController alloc] initWithText:@"Something"];! [self.navigationController pushViewController:secondViewController animated:YES];! [secondViewController release];! }! en SecondViewController.m! - (id)initWithText:(NSString *)someText! {! if (self = [self initWithNibName:@"SecondView" ! bundle:nil]) {! // Custom initialization! self.title = @"Second";! self.text = someText;! }! return self;! }! Pila de vistas: UINavigationController DEMO: push-pop UITabBarController + UINavigationController Muy común combinarlos ...! SimpleFirstController *thirdNavView = [[SimpleFirstController alloc] init];! "thirdNavView.title=@"Alumnos";! "UINavigationController *navigationController3=[[UINavigationController alloc] init];! "[navigationController3 pushViewController:thirdNavView animated:NO]; "! "[thirdNavView release];! "NSArray *controllerArray =[[NSArray alloc] ! initWithObjects:navigationController1,navigationController2,navigationController3, nil]; "[tabController setViewControllers:controllerArray];! ...! " "! Añadimos a los “tabs”de la agenda-base al menos un controlador del tipo “navigation controller” Recopilando … “navigation controlers” Barra de navegación: Barra de “tabs”: UINavigationController UITabBarController Híbrido ... Esquema general • Crear proyecto nuevo - Window-based: solo ventana “base”, ninguna “subview” añadida. - View-based, Navigation-based y Tab-based incluyen automáticamente una subview a la ventana principal inicializada de la manera correspondiente en cada caso - (void)applicationDidFinishLaunching:(UIApplication *)application {! ... ! ó [window addSubview:[(my)viewController view]];! //inicializa por defecto el viewController con appNameViewController (UIView) en MainWindow.xib! ó [window addSubview:[(my)navigationController view]]; ! //inicializa por defecto con RootViewController (que es una tableView) en MainWindow.xib! ó [window addSubview:[(my)tabBarController view]]; //LO MISMO QUE! [window addSubview:(my)tabBarController.view];! [window makeKeyAndVisible];! Esquema general • Crear proyecto nuevo - Window-based: solo ventana “base”, ninguna “subview” añadida. - View-based, Navigation-based y Tab-based incluyen automáticamente una subview a la ventana principal inicializada de la manera correspondiente en cada caso • Y personalizar (my) viewControllers antes de hacer el “addsubview” (código o IB) //inicializar viewController! //inicializar viewController inicial y hacer “push” en la pila del navigationControler //inicializar viewControllers necesarios y “rellenar” vector del tabBarControler Vistas con tablas y “scroll” • Vistas más flexibles: UIScrollView • Para mostrar más cosas de las que caben en la pantalla • Soporta eventos de zoom y de “scroll” • Subclases: UITableView and UITextView Vistas con imágenes Mostrar una imagen “grande” en un “scroll view” UIImage *image = [UIImage imageNamed:@"smartphones.jpg"]; UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; CGRect screenBounds = [[UIScreen mainScreen] bounds]; UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:screenBounds]; [scrollView addSubview:imageView]; scrollView.contentSize = image.size; [self.view addSubview:scrollView];! Vistas con tablas Class: UITableView, UITableViewCell, UITableViewController Protocols: UITableViewDelegate, UITableViewDataSource :UIScrollView, 1columna, varias filas/secciones UITableViewStylePlain Cabecera tabla UITableViewStyleGrouped Cabecera tabla Cabecera sección Cabecera sección Celda Celda Pie sección Pie sección Sección Sección Pie tabla Pie tabla Vistas con tablas Class: UITableView, UITableViewCell, UITableViewController Protocols: UITableViewDelegate, UITableViewDataSource Usually: UITableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> DataSource: Qué se ve (datos) y sus propiedades • NSArray • Cuántas secciones y filas? • Data for a given [section, row] • Contenido de headers y footers. • Propiedades de “edición” de elementos de la tabla: insert, rearrange, delete Delegate: Cómo se ve y qué ocurre con la vista (eventos)? • Tamaño de celdas, filas, cabeceras • Estilo de celdas • “Eventos” de celda_va_a_aparecer • “Eventos” de fila_seleccionada y permisos de ser seleccionado o no • Auto-select/deselect filas si hace falta • Recarga datos antes de hacerse visible. • Otros: edit button, flashes scroll, deja sitio para el teclado si hace falta Vistas con tablas Solución simple Solución más eficiente Otro objeto (datasource: Utilizar un vector para pasar los UITableViewController) pasa los datos a la tabla (como un datos a mostrar [myTableView setList:myListOfStuff]; “delegate”). Los datos se cargan Pero!! Se cargan todos los datos conforme hacen falta! al principio y se quedan en Cuantas secciones visibles? Qué mostrar en celda de sección 1? memoria 5 John Appleseed Vistas con tablas Muchas opciones de configuración en UITableView • Apariencia de filas y celdas: estilos de celda(UITableViewCellStyleDefault,...), otros “accesorios” (UITableViewCellAccessoryType) • Responder a eventos de selección: didSelectRowAtIndexPath:(NSIndexPath *) indexPath; willSelectRowAtIndexPath (NSIndexPath *)indexPath UITableViewController crea automáticamente un Table view, es su “delegate” y “datasource”. • El • Se ocupa de acciones por defecto: reloadData al principio, deselecciona filas al navegar hacia atrás, … Vistas con tablas Muchas opciones de configuración en UITableView Cargar datos bajo demanda: cuando una fila se hace visible (automático) o cuando se llama explicitamente “reloadData” - (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; [self.tableView reloadData]; } • Re-utilizar celdas UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@“MyIdentifier”]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:... reuseIdentifier:@“MyIdenifier”] autorelease]; } • Personalizar celdas (tanto apariencia como atributos de “datos”) Vistas con tablas DEMO: recipes Añadimos vista de tabla a la “agenda” base (más avanzado: ejemplo “The Elements”)