2012-07-10 30 views
11

Este problema me está volviendo loco. Intento cambiar el viewController cuando el usuario cambia la "pestaña" seleccionada del control segmentado. He pasado un par de horas investigando y no he podido encontrar una respuesta que funcione o se haga a través del guión gráfico.Cambiar controlador de vista cuando el Control segmentado cambia

Realmente me molesta desde que configurar una aplicación de pestañas es tan fácil, pero tratar de usar el control segmentado como la aplicación de pestañas simplemente no funciona. Ya sé cómo detectar qué índice se selecciona en el control segmentado. ¿Cómo puedo conseguir esto?

Muchas gracias.

+0

¿Estás tratando de cambiar un _view_ o un _view controller_? Son dos cosas diferentes. Si es lo último, te sugiero que pongas todo en un controlador de vista y muestres u ocultes las subvistas según se necesiten. –

+0

Bueno, soy muy nuevo en iOS, lo más simple que me viene a la mente es cambiar ViewController como lo hace una aplicación con pestañas. ¿Sugiere hacer varias vistas y administrarlas con el mismo controlador de vista? Si es así, ¿cómo puedo hacer eso? Muchas gracias –

Respuesta

4

Yo diría que es mucho sim Para cambiar las subvistas dentro de un UIViewController, puede configurar sus subvistas en sus guiones gráficos y conectarlas con IBOulets en su controlador. Puede establecer la propiedad hidden de sus vistas en SÍ o NO, dependiendo del control que se haya hecho clic.

Ahora, si utiliza el enfoque de @Robotic Cat, que también es una buena solución, puede tener un poco más de modularidad en el funcionamiento de su aplicación, teniendo en cuenta que debe colocar toda su lógica en un controlador utilizando la solución que presenté .

+0

Me gusta su sugerencia, acaba de probarlo en xcode y se ve bien y es fácil de implementar. Mi única preocupación es que es ineficaz tener vistas ocultas en el fondo? –

+1

No he leído nada en los documentos del desarrollador que vaya en contra de esto, aunque debe tener en cuenta que si agrega muchos elementos visuales, ocupará memoria, así que hágalo sabiamente. Para evitar esto, puedes instigar todo lo que necesites sobre la marcha, aunque creo que la sobrecarga de tener todos los elementos ya configurados es mínima. Solo tengo 4 subvistas, cada una con 1 o 2 campos de texto, por ejemplo. – 8vius

+1

En una de mis aplicaciones para iPad, tengo un controlador de vista que tiene 7 subvistas que pueden mostrarse u ocultarse, cada una con su propio conjunto de controles. En total, hay alrededor de 60 vistas y subvídeos (etiquetas, botones, etc.). No noto ninguna lentitud o vacilación, y Profier no revela grandes picos en la memoria o la CPU. Obviamente, debes probar tu propia solución a fondo, pero dudo que tengas un problema. –

0

UISegmentedControl es un poco diferente ya que no tiene un protocolo de delegado, debe usar el estilo "agregar objetivo". En su caso, lo que desea hacer es agregar un objetivo para que se le notifique cuando el UISegmentedControl cambie (lo que probablemente sea el controlador de vista padre), y luego ese objetivo puede manejar el cambio de pestañas.

Por ejemplo:

[self.mainSegmentedControl addTarget:self action:@selector(changedSegmentedControl:) forControlEvents:UIControlEventValueChanged]; 

En este ejemplo, el código se invoca desde algún punto de vista/controlador que tiene acceso a la variable para el control segmentado. Nos agregamos para obtener el método cambiadoSegmentedControl: invocado.

entonces habría otro método de este modo:

- (void)changedSegmentedControl:(id)sender 
{ 
    UISegmentedControl *ctl = sender; 
    NSLog(@"Changed value of segmented control to %d", ctl.selectedSegmentIndex); 
    // Code to change View Controller goes here 
} 

Nota: este es el código no probado por escrito de la memoria - por favor consulte la documentación correspondiente.

42

NOTA: Respuesta actualizado con el código de controlador de vista de contención para iOS 5+ incluyendo la sección @interface

En una aplicación mío, tengo un controlador de vista con un control Segmento en la barra de navegación y haciendo clic en el "pestañas" cambia los controles de vista. La idea básica es tener una variedad de controladores de visualización y cambiar entre ellos utilizando el Índice de segmentos (y el indexDidChangeForSegmentedControl IBAction.

Código de ejemplo (iOS 5 o posterior) de mi aplicación (esto es para 2 controladores de vista pero es trivial) . extenderse a múltiples controladores de vista); el código es ligeramente más largo que para iOS 4 pero mantendrá intacto el gráfico de objetos también, se utiliza ARC: ejemplo

@interface MyViewController() 
// Segmented control to switch view controllers 
@property (weak, nonatomic) IBOutlet UISegmentedControl *switchViewControllers; 

// Array of view controllers to switch between 
@property (nonatomic, copy) NSArray *allViewControllers; 

// Currently selected view controller 
@property (nonatomic, strong) UIViewController *currentViewController; 
@end 

@implementation UpdateScoreViewController 
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 
- (void)viewDidLoad { 
    [super viewDidLoad]; 

    // Create the score view controller 
    ViewControllerA *vcA = [self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerA"]; 

    // Create the penalty view controller 
    ViewControllerB *vcB = [self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerB"]; 

    // Add A and B view controllers to the array 
    self.allViewControllers = [[NSArray alloc] initWithObjects:vcA, vcB, nil]; 

    // Ensure a view controller is loaded 
    self.switchViewControllers.selectedSegmentIndex = 0; 
    [self cycleFromViewController:self.currentViewController toViewController:[self.allViewControllers objectAtIndex:self.switchViewControllers.selectedSegmentIndex]]; 
} 

#pragma mark - View controller switching and saving 

- (void)cycleFromViewController:(UIViewController*)oldVC toViewController:(UIViewController*)newVC { 

    // Do nothing if we are attempting to swap to the same view controller 
    if (newVC == oldVC) return; 

    // Check the newVC is non-nil otherwise expect a crash: NSInvalidArgumentException 
    if (newVC) { 

     // Set the new view controller frame (in this case to be the size of the available screen bounds) 
     // Calulate any other frame animations here (e.g. for the oldVC) 
     newVC.view.frame = CGRectMake(CGRectGetMinX(self.view.bounds), CGRectGetMinY(self.view.bounds), CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds)); 

     // Check the oldVC is non-nil otherwise expect a crash: NSInvalidArgumentException 
     if (oldVC) { 

      // Start both the view controller transitions 
      [oldVC willMoveToParentViewController:nil]; 
      [self addChildViewController:newVC]; 

      // Swap the view controllers 
      // No frame animations in this code but these would go in the animations block 
      [self transitionFromViewController:oldVC 
           toViewController:newVC 
             duration:0.25 
             options:UIViewAnimationOptionLayoutSubviews 
            animations:^{} 
            completion:^(BOOL finished) { 
             // Finish both the view controller transitions 
             [oldVC removeFromParentViewController]; 
             [newVC didMoveToParentViewController:self]; 
             // Store a reference to the current controller 
             self.currentViewController = newVC; 
            }]; 

     } else { 

      // Otherwise we are adding a view controller for the first time 
      // Start the view controller transition 
      [self addChildViewController:newVC]; 

      // Add the new view controller view to the ciew hierarchy 
      [self.view addSubview:newVC.view]; 

      // End the view controller transition 
      [newVC didMoveToParentViewController:self]; 

      // Store a reference to the current controller 
      self.currentViewController = newVC; 
     } 
    } 
} 

- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl *)sender { 

    NSUInteger index = sender.selectedSegmentIndex; 

    if (UISegmentedControlNoSegment != index) { 
     UIViewController *incomingViewController = [self.allViewControllers objectAtIndex:index]; 
     [self cycleFromViewController:self.currentViewController toViewController:incomingViewController]; 
    } 

} 
@end 

original (iOS 4 o antes):

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 
- (void)viewDidLoad { 
    [super viewDidLoad]; 

    // Create the score view controller 
    AddHandScoreViewController *score = [self.storyboard instantiateViewControllerWithIdentifier:@"AddHandScore"]; 

    // Create the penalty view controller 
    AddHandPenaltyViewController *penalty = [self.storyboard instantiateViewControllerWithIdentifier:@"AddHandPenalty"]; 

    // Add Score and Penalty view controllers to the array 
    self.allViewControllers = [[NSArray alloc] initWithObjects:score, penalty, nil]; 

    // Ensure the Score controller is loaded 
    self.switchViewControllers.selectedSegmentIndex = 0; 
    [self switchToController:[self.allViewControllers objectAtIndex:self.switchViewControllers.selectedSegmentIndex]]; 
} 

#pragma mark - View controller switching and saving 

- (void)switchToController:(UIViewController *)newVC 
{ 
    if (newVC) { 
     // Do nothing if we are in the same controller 
     if (newVC == self.currentViewController) return; 

     // Remove the current controller if we are loaded and shown 
     if([self.currentViewController isViewLoaded]) [self.currentViewController.view removeFromSuperview]; 

     // Resize the new view controller 
     newVC.view.frame = CGRectMake(CGRectGetMinX(self.view.bounds), CGRectGetMinY(self.view.bounds), CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds)); 

     // Add the new controller 
     [self.view addSubview:newVC.view]; 

     // Store a reference to the current controller 
     self.currentViewController = newVC; 
    } 
} 

- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl *)sender { 

    NSUInteger index = sender.selectedSegmentIndex; 

    if (UISegmentedControlNoSegment != index) { 
     UIViewController *incomingViewController = [self.allViewControllers objectAtIndex:index]; 
     [self switchToController:incomingViewController]; 
    } 

} 
+0

Una solución realmente agradable. Gracias por compartir esto. – Mike

+0

@Robotic Cat: Estoy un poco confundido sobre por qué configura el marco del controlador de vista hijo para que sea el mismo que el controlador de vista principal. ¿Este controlador de vista principal no contiene el UISegmentedControl? Si es así, ¿el controlador de vista infantil no lo ocultaría? – Marplesoft

+0

@Marplesoft: por lo general, el 'UISegmentedControl' está en la barra de navegación. Obviamente, si su 'UISegmentedControl' está en su controlador de vista, debe establecer las restricciones o el marco de su autolayout en los valores correctos para su aplicación. –

0

Eche un vistazo a este pod: https://github.com/xmartlabs/XLMailBoxContainer. Hace la animación de la interfaz de usuario entre los controladores de vista. Este controlador de vista puede extender UITableViewController o cualquier otro controlador de vista.

Espero que esto te ayude!

Cuestiones relacionadas