2012-02-02 11 views
36

Estoy intentando algo muy simple pero de alguna manera no puedo hacer que funcione. Todo lo que intento hacer es cambiar entre 2 Controladores de Vista usando un UISegmentedControl como lo puede ver, por ejemplo, en la aplicación App Store en la pestaña Destacados.Conmutar ViewControllers con UISegmentedControl en iOS5

Estoy usando iOS5 y Storyboards.

Aquí está mi línea de storyboards hasta:

enter image description here

Así que tienen una raíz Vista Controlador y dos UITableViews - Este 2 TableViews que quiero cambiar.

Así es como el archivo de implementación parece

#import "SegmentedLocationViewController.h" 
#import "PastEventsLocationViewController.h" 
#import "FutureEventsLocationViewController.h" 

@interface SegmentedLocationViewController() 
@property (weak, nonatomic) IBOutlet UISegmentedControl *segmentedControl; 
@property (strong, nonatomic) NSArray *viewControllers; 
@end 


@implementation SegmentedLocationViewController 

@synthesize segmentedControl = _segmentedControl; 
@synthesize viewControllers = _viewControllers; 

- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl*)segmentedControl 
{ 
    NSLog(@"index: %d", segmentedControl.selectedSegmentIndex); 
} 

- (void)setupViewControllers 
{ 
    PastEventsLocationViewController *pastEventsLocationViewController = [[PastEventsLocationViewController alloc] initWithStyle:UITableViewStylePlain]; 
    FutureEventsLocationViewController *futureEventsLocationViewController = [[FutureEventsLocationViewController alloc] initWithStyle:UITableViewStylePlain]; 

    self.viewControllers = [NSArray arrayWithObjects:pastEventsLocationViewController, futureEventsLocationViewController, nil]; 
} 

- (void)setupUI 
{ 
    [self.segmentedControl addTarget:self action:@selector(indexDidChangeForSegmentedControl:) forControlEvents:UIControlEventValueChanged]; 
} 

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

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    return YES; 
} 

@end 

puedo activar el evento interruptor y abrir una sesión el índice seleccionado en ese momento. Pero no tengo idea de dónde ir desde aquí.

Tal vez alguien pueda dirigir mi atención hacia una determinada dirección ...?

+1

¿Has pensado en volver a cargar TableView con diferentes valores? –

+0

Tienes razón. Voy a verificar eso ahora. Tal vez piense que es demasiado complicado ... – MrBr

Respuesta

82

Este código funciona bastante bien para su propósito, lo uso para una de mis nuevas aplicaciones.
Utiliza las nuevas API UIViewController de contención que permiten UIViewControllers dentro de sus propias UIViewControllers sin las molestias de la materia reenviar manualmente como viewDidAppear:

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // add viewController so you can switch them later. 
    UIViewController *vc = [self viewControllerForSegmentIndex:self.typeSegmentedControl.selectedSegmentIndex]; 
    [self addChildViewController:vc]; 
    vc.view.frame = self.contentView.bounds; 
    [self.contentView addSubview:vc.view]; 
    self.currentViewController = vc; 
} 
- (IBAction)segmentChanged:(UISegmentedControl *)sender { 
    UIViewController *vc = [self viewControllerForSegmentIndex:sender.selectedSegmentIndex]; 
    [self addChildViewController:vc]; 
    [self transitionFromViewController:self.currentViewController toViewController:vc duration:0.5 options:UIViewAnimationOptionTransitionFlipFromBottom animations:^{ 
     [self.currentViewController.view removeFromSuperview]; 
     vc.view.frame = self.contentView.bounds; 
     [self.contentView addSubview:vc.view]; 
    } completion:^(BOOL finished) { 
     [vc didMoveToParentViewController:self]; 
     [self.currentViewController removeFromParentViewController]; 
     self.currentViewController = vc; 
    }]; 
    self.navigationItem.title = vc.title; 
} 

- (UIViewController *)viewControllerForSegmentIndex:(NSInteger)index { 
    UIViewController *vc; 
    switch (index) { 
     case 0: 
      vc = [self.storyboard instantiateViewControllerWithIdentifier:@"FooViewController"]; 
      break; 
     case 1: 
      vc = [self.storyboard instantiateViewControllerWithIdentifier:@"BarViewController"]; 
      break; 
    } 
    return vc; 
} 

Tengo esta materia del capítulo 22 del libro de Ray Wenderlichs iOS5 by tutorial. Lamentablemente no tengo un enlace público a un tutorial. Pero hay un video WWDC 2011 titulado "Implementación de UIViewController contención"

EDITAR

self.typeSegmentedControl es salida para su UISegmentedControl

self.contentView se toma para su vista de contenedor

self.currentViewController es sólo una propiedad que estamos utilizando para almacenar nuestro actualmente usado UIViewController

+0

No lo hice con los guiones gráficos, pero cuando uso tu código con archivos semilla funciona ... Así que gracias, obtienes mi voto;) – MrBr

+3

Este hombre rockero. Acabo de descubrir [self storyboard] después de 2 meses. ¡¡Gracias!! –

+0

Esto podría parecer una pregunta estúpida, pero cuando empiezo desde cero recibo problemas como este Property 'typeSegmentedControl' no encontrado en el objeto de tipo 'ViewController *' Probablemente estoy haciendo algo estúpido, ¿no es así? – user379468

0

Puede incrustar su controlador de vista inicial en un controlador de navegación. Haga eso seleccionando el controlador de vista en el guión gráfico, luego Editor-> Insertar en> Controlador de navegación.

En su indexDidChangeForSegmentedControl: método sólo tiene que pulsar el controlador de vista correspondiente a la pila de navegación:

- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl*)segmentedControl 
{ 
    [self.navigationController pushViewController:[self.viewControllers objectAtIndex:[segmentedControl.selectedIndex]] animated:YES]; 

} 

Sin embargo, su enfoque hace no demasiado sentido en absoluto cuando está utilizando guiones gráficos. No sé si puede cablear un solo botón de control segmentado a un controlador de visualización mediante segues. Solo inténtalo.

8

¡Es la solución de Matthias Bauch, pero de todos modos pensé en compartirla en Swift! Editar: Agregando un enlace a una aplicación de demostración lista para usar Swift 2.0. https://github.com/ahmed-abdurrahman/taby-segmented-control

var currentViewController: UIViewController? 
@IBOutlet weak var contentView: UIView! 
@IBOutlet weak var segmentedControl: UISegmentedControl! 

@IBAction func switchHappeningTabs(sender: UISegmentedControl) { 
    if let vc = viewControllerForSelectedSegmentIndex(sender.selectedSegmentIndex) { 
     self.addChildViewController(vc) 
     self.transitionFromViewController(self.currentViewController!, toViewController: vc, duration: 0.5, options: UIViewAnimationOptions.TransitionFlipFromRight, animations: { 
      self.currentViewController!.view.removeFromSuperview() 
      vc.view.frame = self.contentView.bounds 
      self.contentView.addSubview(vc.view) 
      }, completion: { finished in 
       vc.didMoveToParentViewController(self) 
       self.currentViewController!.removeFromParentViewController() 
       self.currentViewController = vc 
      } 
     )   
    } 
} 

override func viewDidLoad() { 
    super.viewDidLoad() 

    if let vc = self.viewControllerForSelectedSegmentIndex(self.segmentedControl.selectedSegmentIndex) { 
     self.addChildViewController(vc) 
     self.contentView.addSubview(vc.view) 
     self.currentViewController = vc 
    } 
} 

func viewControllerForSelectedSegmentIndex(index: Int) -> UIViewController? { 
    var vc: UIViewController? 
    switch index { 
    case 0: 
      vc = self.storyboard?.instantiateViewControllerWithIdentifier("FooViewController") as? UIViewController 
    case 1: 
      vc = self.storyboard?.instantiateViewControllerWithIdentifier("BarViewController") as? UIViewController 
    default: 
     return nil 
    } 

    return vc 
} 
+0

¡Muchas gracias! Esto hizo que mi día :) – AlexB

+0

Claro, es un placer :) – Abdurrahman

2

Para alguien desea implementar el mismo en Swift

import UIKit 

class HomeController: UIViewController { 

    var currentViewController:UIViewController? 

    @IBOutlet weak var homeController: UIView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     let initialController:UIViewController = self.viewControllerForSegmentedIndex(0) 

     self.addChildViewController(initialController) 

     initialController.view.frame = self.homeController.bounds 
     self.homeController.addSubview(initialController.view) 
     self.currentViewController = initialController 

    } 

    @IBAction func segmentChanged(sender: UISegmentedControl) { 

     let viewCOntroller:UIViewController = viewControllerForSegmentedIndex(sender.selectedSegmentIndex) 

     self.addChildViewController(viewCOntroller) 

     self.transitionFromViewController(self.currentViewController!, toViewController: viewCOntroller, duration: 0.5, options: UIViewAnimationOptions.TransitionFlipFromBottom, animations: { 
      self.currentViewController?.view.removeFromSuperview() 
      viewCOntroller.view.frame = self.homeController.bounds 
      self.homeController.addSubview(viewCOntroller.view) 

      }, completion:{ finished in 

       viewCOntroller.didMoveToParentViewController(self) 
       self.currentViewController?.removeFromParentViewController() 
       self.currentViewController = viewCOntroller 

     }) 

    } 
    func viewControllerForSegmentedIndex(index:Int) -> UIViewController { 
     var viewController:UIViewController? 
     switch index { 
     case 0: 
      viewController = self.storyboard?.instantiateViewControllerWithIdentifier("StoryboardIdForFirstController") 
      break 
     case 1: 
      viewController = self.storyboard?.instantiateViewControllerWithIdentifier("StoryboardIdForSecondController") 
      break 
     case 2: 
      viewController = self.storyboard?.instantiateViewControllerWithIdentifier("StoryboardIdForThirdController") 
      break 
     default: 
      break 
     } 
     return viewController! 
    } 
} 

vista Storyboard

enter image description here

2

A es controlador de vista raíz, y B, C es sub controlador de vista . Al hacer clic en segmento, agregue el controlador de subvista.

resultado

result

diseño

design

código

import UIKit 

class SegmentViewController: UIViewController { 

    @IBOutlet weak var containerView: UIView! 

    var leftViewController: LeftViewController! 
    var rightViewController: RightViewController! 


    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 

     if let sb = storyboard { 
      leftViewController = sb.instantiateViewControllerWithIdentifier("leftViewController") as! LeftViewController 

      switchViewController(from: nil, to: leftViewController) 
     } else { 
      print("storyboard is nil") 
     } 
    } 

    func switchViewController(from fromVC: UIViewController?, to toVC: UIViewController?) { 
     if let from = fromVC { 
      from.willMoveToParentViewController(nil) 
      from.view.removeFromSuperview() 
      from.removeFromParentViewController() 
     } else { 
      print("fromVC is nil") 
     } 

     if let to = toVC { 
      self.addChildViewController(to) 
      to.view.frame = CGRectMake(0, 0, containerView.frame.width, containerView.frame.height) 
      self.containerView.insertSubview(to.view, atIndex: 0) 
      to.didMoveToParentViewController(self) 
     } else { 
      print("toVC is nil") 
     } 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 

     removeViewController() 
    } 

    func removeViewController() { 
     if let leftVC = leftViewController { 
      if let _ = leftVC.parentViewController { 
       print("leftVC is using") 
      } else { 
       print("set leftVC = nil") 
       leftViewController = nil 
      } 
     } 

     if let rightVC = rightViewController { 
      if let _ = rightVC.parentViewController { 
       print("rightVC is using") 
      } else { 
       print("set rightVC = nil") 
       rightViewController = nil 
      } 
     } 
    } 


    @IBAction func onSegmentValueChanged(sender: UISegmentedControl) { 
     UIView.beginAnimations("xxx", context: nil) 
     UIView.setAnimationDuration(0.4) 
     UIView.setAnimationCurve(.EaseInOut) 

     switch sender.selectedSegmentIndex { 
     case 0: 
      UIView.setAnimationTransition(.FlipFromRight, forView: self.containerView, cache: true) 

      if let leftVC = leftViewController { 
       switchViewController(from: rightViewController, to: leftVC) 
      } else { 
       if let sb = storyboard { 
        leftViewController = sb.instantiateViewControllerWithIdentifier("leftViewController") as! LeftViewController 
        switchViewController(from: rightViewController, to: leftViewController) 
       } else { 
        print("storyboard is nil") 
       } 
      } 
     default: 
      UIView.setAnimationTransition(.FlipFromLeft, forView: self.containerView, cache: true) 

      if let rightVC = rightViewController { 
       switchViewController(from: leftViewController, to: rightVC) 
      } else { 
       if let sb = storyboard { 
        rightViewController = sb.instantiateViewControllerWithIdentifier("rightViewController") as! RightViewController 
        switchViewController(from: leftViewController, to: rightViewController) 
       } else { 
        print("storyboard is nil") 
       } 
      } 
     } 

     UIView.commitAnimations() 
    } 
}