iphone - how - swift 4 segmented control example
UISegmentedControl Best Practice (3)
Estoy tratando de encontrar la "mejor" manera de usar un UISegmentedControl
para una aplicación de iPhone. He leído algunas publicaciones aquí en stackoverflow y he visto las ideas de algunas personas, pero no puedo encontrar la mejor manera de hacerlo. Los posts a los que me refiero son:
Cambio de vistas desde UISegmentedControl y ¿Cómo uso un UISegmentedControl para cambiar las vistas?
Parecería que las opciones son:
- Agregue cada una de las vistas en IB y colóquelas una encima de la otra, luego muéstrelas / escóndalas
- Cree cada una de las subvistas por separado en IB, luego cree un contenedor en la vista principal para completar con la subvista que necesita
- Configure una vista en
UIView
muy alta o muy ancha yUIView
a la izquierda / derecha o arriba / abajo según el segmento seleccionado - Use un
UITabBarController
para intercambiar las subvistas: parece una tontería - Para las tablas, vuelva a cargar la tabla y en
cellForRowAtIndex
ycellForRowAtIndex
la tabla desde diferentes orígenes de datos o secciones según la opción de segmento seleccionada (no es el caso de mi aplicación)
Entonces, ¿cuál es el mejor enfoque para los enfoques de subvista / no-tabla? ¿Cuál es la más fácil de implementar? ¿Podría compartir algún código de ejemplo para el enfoque?
¡Gracias!
Aquí hay un gran tutorial que explica este concepto más a fondo: http://redartisan.com/2010/5/26/uisegmented-control-view-switching
y la ubicación de github: https://github.com/crafterm/SegmentedControlExample.git
He encontrado este requisito también en una aplicación de iPad.
La solución a la que llegué fue crear controladores de vista especializados para cada estilo de vista para manejar la lógica de negocios relacionada con esos puntos de vista (es decir, relacionados con cada segmento), y agregarlos / eliminarlos como subvistas a un controlador "administrador" en respuesta a Cambios en el índice del segmento seleccionado.
Para hacer esto, uno tiene que crear una subclase UIViewController adicional que administre los cambios de UISegmentedControl y agregue / elimine las subvistas.
El código a continuación hace todo esto, también se ocupa de algunas advertencias / extras:
- viewWillAppear / viewWillDisappear / etc, no se invoca automáticamente en las subvistas y debe indicarse a través del controlador de "administración"
- viewWillAppear / viewWillDisappear / etc, no se invoca en el controlador ''de gestión'' cuando está dentro de un controlador de navegación, por lo tanto, el delegado del controlador de navegación
- Si desea ingresar a una pila de navegación desde la subvista de un segmento, debe volver a llamar a la vista de "administración" para hacerlo, ya que la subvista se creó fuera de la jerarquía de navegación y no tendrá Una referencia al controlador de navegación.
- Si se usa dentro de un escenario de controlador de navegación, el botón Atrás se establece automáticamente en el nombre del segmento.
Interfaz:
@interface SegmentManagingViewController : UIViewController <UINavigationControllerDelegate> {
UISegmentedControl * segmentedControl;
UIViewController * activeViewController;
NSArray * segmentedViewControllers;
}
@property (nonatomic, retain) IBOutlet UISegmentedControl * segmentedControl;
@property (nonatomic, retain) UIViewController * activeViewController;
@property (nonatomic, retain) NSArray * segmentedViewControllers;
@end
Implementación:
@interface SegmentManagingViewController ()
- (void)didChangeSegmentControl:(UISegmentedControl *)control;
@end
@implementation SegmentManagingViewController
@synthesize segmentedControl, activeViewController, segmentedViewControllers;
- (void)viewDidLoad {
[super viewDidLoad];
UIViewController * controller1 = [[MyViewController1 alloc] initWithParentViewController:self];
UIViewController * controller2 = [[MyViewController2 alloc] initWithParentViewController:self];
UIViewController * controller3 = [[MyViewController3 alloc] initWithParentViewController:self];
self.segmentedViewControllers = [NSArray arrayWithObjects:controller1, controller2, controller3, nil];
[controller1 release];
[controller2 release];
[controller3 release];
self.navigationItem.titleView = self.segmentedControl =
[[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"Seg 1", @"Seg 2", @"Seg 3", nil]];
self.segmentedControl.selectedSegmentIndex = 0;
self.segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
[self.segmentedControl addTarget:self action:@selector(didChangeSegmentControl:) forControlEvents:UIControlEventValueChanged];
[self didChangeSegmentControl:self.segmentedControl]; // kick everything off
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.activeViewController viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.activeViewController viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.activeViewController viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.activeViewController viewDidDisappear:animated];
}
#pragma mark -
#pragma mark UINavigationControllerDelegate control
// Required to ensure we call viewDidAppear/viewWillAppear on ourselves (and the active view controller)
// inside of a navigation stack, since viewDidAppear/willAppear insn''t invoked automatically. Without this
// selected table views don''t know when to de-highlight the selected row.
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
[viewController viewDidAppear:animated];
}
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
[viewController viewWillAppear:animated];
}
#pragma mark -
#pragma mark Segment control
- (void)didChangeSegmentControl:(UISegmentedControl *)control {
if (self.activeViewController) {
[self.activeViewController viewWillDisappear:NO];
[self.activeViewController.view removeFromSuperview];
[self.activeViewController viewDidDisappear:NO];
}
self.activeViewController = [self.segmentedViewControllers objectAtIndex:control.selectedSegmentIndex];
[self.activeViewController viewWillAppear:NO];
[self.view addSubview:self.activeViewController.view];
[self.activeViewController viewDidAppear:NO];
NSString * segmentTitle = [control titleForSegmentAtIndex:control.selectedSegmentIndex];
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:segmentTitle style:UIBarButtonItemStylePlain target:nil action:nil];
}
#pragma mark -
#pragma mark Memory management
- (void)dealloc {
self.segmentedControl = nil;
self.segmentedViewControllers = nil;
self.activeViewController = nil;
[super dealloc];
}
@end
Espero que esto ayude.
Iría con la segunda opción que mencionas, creando las subvistas en IB y cambiándolas dentro y fuera de la vista principal. Esta sería una buena oportunidad para usar UIViewController
, sin subcategorizar: en su configuración inicial, cree un controlador usando -initWithNibName:bundle:
(donde el primer parámetro es el nombre del NIB que contiene la subvista individual, y el segundo parámetro es nil
) y agregue su view
como una subvista de su vista principal según sea necesario. Esto ayudará a mantener su huella de memoria baja: el comportamiento predeterminado de un UIViewController
cuando recibe una advertencia de memoria es liberar su vista si no tiene supervisión. Mientras elimine vistas ocultas de la jerarquía de vistas, puede mantener los controladores en la memoria y no preocuparse por liberar nada.
(editado en respuesta al comentario :)
No necesita subclasificar UIViewController
, pero sí necesita XIB separados para cada vista. Tampoco es necesario que agregue nada a la vista que contiene en IB.
Las variables de instancia, en la interfaz de cualquier clase están manejando todo esto:
UIViewController *controllerOne;
UIViewController *controllerTwo;
UIViewController *currentController;
IBOutlet UIView *theContainerView;
En su configuración ( -applicationDidFinishLaunching:
o lo que sea)
controllerOne = [[UIViewController alloc] initWithNibName:@"MyFirstView" bundle:nil];
controllerTwo = [[UIViewController alloc] initWithNibName:@"MySecondView" bundle:nil];
Para cambiar a un controlador:
- (void)switchToController:(UIViewController *)newCtl
{
if(newCtl == currentController)
return;
if([currentController isViewLoaded])
[currentController.view removeFromSuperview];
if(newCtl != nil)
[theContainerView addSubview:newCtl.view];
currentController = newCtl;
}
Entonces simplemente llama a eso con, por ejemplo,
[self switchToController:controllerOne];