![Page 1: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/1.jpg)
Desarrollo de aplicaciones para dispositivos móviles:
Programación para iOS
Luis Montesano ' Bob D/ Nvsjmmp
![Page 2: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/2.jpg)
• Ana Cris Murillo
Contacto: [email protected]
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: [email protected]
Profesor del Dpto. de Informática e Ing. de Sistemas, Universidad de Zaragoza.
Investigación en aprendizaje y robótica
Profesorado
![Page 3: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/3.jpg)
• 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)
Materiales, documentación, código ...
![Page 4: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/4.jpg)
Í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
![Page 5: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/5.jpg)
“Hello World”: ���Objective C, Xcode, IB.
![Page 6: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/6.jpg)
MVC en una vista “simple”
![Page 7: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/7.jpg)
MVC en una vista “simple”
• Patrón Model-View-Controller
• Una clase
• Un viewController sencillo
![Page 8: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/8.jpg)
Diseño de aplicaciones: opciones de navegación
![Page 9: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/9.jpg)
Control de navegación: “navigation controlers”
Barra de navegación: UINavigationController
Barra de “tabs”: UITabBarController
Híbrido ...
![Page 10: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/10.jpg)
Vector de vistas: UITabBarController
• Controlador de la vista seleccionada
• Iconos/nombres de todos los controladores de vistas
![Page 11: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/11.jpg)
- (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
![Page 12: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/12.jpg)
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
![Page 13: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/13.jpg)
Vector de vistas: UITabBarController
DEMO: MyTab
Añadimos “vector” de “tabs” a la agenda-base (con uno de los tabs la vista “sencilla”)
![Page 14: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/14.jpg)
Pila de vistas: UINavigationController
• Título del controlador de la vista encima de la pila.
• Título del controlador de la vista anterior
• Vista encima de la pila
• Barra de herramientas de la vista encima de la pila
![Page 15: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/15.jpg)
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 el título por algún “control”: self.navigationItem.titleView = segmentedControl;
• Botón 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;
![Page 16: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/16.jpg)
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
![Page 17: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/17.jpg)
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
![Page 18: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/18.jpg)
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
![Page 19: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/19.jpg)
Pila de vistas: UINavigationController
DEMO: push-pop
![Page 20: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/20.jpg)
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]; !
... !
![Page 21: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/21.jpg)
Añadimos a los “tabs”de la agenda-base al menos un controlador del tipo “navigation controller”
![Page 22: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/22.jpg)
Recopilando …
![Page 23: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/23.jpg)
“navigation controlers”
Barra de navegación: UINavigationController
Barra de “tabs”: UITabBarController
Híbrido ...
![Page 24: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/24.jpg)
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]; !
![Page 25: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/25.jpg)
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
![Page 26: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/26.jpg)
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
![Page 27: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/27.jpg)
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]; !
![Page 28: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/28.jpg)
Vistas con tablas Class: UITableView, UITableViewCell, UITableViewController Protocols: UITableViewDelegate, UITableViewDataSource
UITableViewStylePlain UITableViewStyleGrouped
Cabecera tabla Cabecera tabla
Pie tabla
Pie tabla
Cabecera sección Cabecera sección
Pie sección Pie sección
Sección Sección
Celda Celda
:UIScrollView, 1columna, varias filas/secciones
![Page 29: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/29.jpg)
Vistas con tablas
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
Class: UITableView, UITableViewCell, UITableViewController Protocols: UITableViewDelegate, UITableViewDataSource
![Page 30: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/30.jpg)
Solución simple Solución más eficiente
Utilizar un vector para pasar los datos a mostrar [myTableView setList:myListOfStuff]; Pero!! Se cargan todos los datos al principio y se quedan en memoria
Otro objeto (datasource: UITableViewController) pasa los datos a la tabla (como un “delegate”). Los datos se cargan conforme hacen falta!
Cuantas secciones visibles? Qué mostrar en celda de sección 1?
5 John Appleseed
Vistas con tablas
![Page 31: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/31.jpg)
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
• El UITableViewController crea automáticamente un Table view, es su “delegate” y “datasource”.
• Se ocupa de acciones por defecto: reloadData al principio, de-selecciona filas al navegar hacia atrás, …
Vistas con tablas
![Page 32: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/32.jpg)
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
![Page 33: Desarrollo de aplicaciones para dispositivos móviles ...webdiis.unizar.es/~anacris/curso_ios/1.navegacion.pdfÍndice de este fin de semana! • Repaso opciones diseño vistas básico!-](https://reader035.vdocumento.com/reader035/viewer/2022071219/6055394c3e3f8729ea7b14f0/html5/thumbnails/33.jpg)
Vistas con tablas
DEMO: recipes Añadimos vista de tabla a la “agenda” base (más avanzado: ejemplo “The Elements”)