2012-02-02 13 views
36

Sto provando qualcosa di molto semplice ma in qualche modo non riesco a farlo funzionare. Tutto quello che cerco di fare è passare da 2 View Controller usando un UISegmentedControl, come si può vedere ad esempio nell'applicazione App Store nella scheda Highlights.Cambio di ViewController con UISegmentedControl in iOS5

Sto usando iOS5 e Storyboard.

Ecco la mia linea Storyboad up:

enter image description here

quindi ho una radice View Controller e due UITableViews - Questo 2 TableViews che voglio cambiare.

Ecco come file di implementazione sembra

#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 

posso attivare l'evento interruttore e può accedere l'indice attualmente selezionato. Ma non ho idea di dove andare da qui.

Forse qualcuno può rivolgere la mia attenzione verso una determinata direzione ...?

+1

hai mai pensato di ricaricare il TableView con valori diversi? –

+0

Hai ragione. Lo controllerò ora. Potrei pensare che sia troppo complicato ... – MrBr

risposta

82

Questo codice funziona piuttosto bene per il tuo scopo, lo uso per una delle mie nuove app.
utilizza le nuove API UIViewController contenimento che permettono UIViewControllers all'interno del proprio UIViewControllers senza i problemi di roba spedizioni manualmente come 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; 
} 

ho ricevuto questa roba dal capitolo 22 di Ray Wenderlichs libro iOS5 by tutorial. Purtroppo non ho un link pubblico ad un tutorial. Ma c'è un video WWDC 2011 intitolato "Implementazione UIViewController contenimento"

EDIT

self.typeSegmentedControl è presa per il vostro UISegmentedControl

self.contentView è uscita per la visualizzazione contenitore

self.currentViewController è solo una proprietà che stiamo usando per memorizzare il nostro attualmente utilizzato UIViewController

+0

Non l'ho fatto con gli storyboard ma quando uso il tuo codice con i file di pennini funziona ... Quindi grazie hai il mio voto;) – MrBr

+3

Questo uomo di rocce. Ho appena scoperto [auto storyboard] dopo 2 mesi. Grazie!! –

+0

Questa potrebbe sembrare una domanda stupida, ma quando si inizia da zero ottengo problemi come questo tipo 'TypeSegmentedControl' non trovato su oggetto di tipo 'ViewController *' Probabilmente sto facendo qualcosa di stupido non sono io – user379468

0

È possibile incorporare il controller di visualizzazione iniziale in un controller di navigazione. Puoi farlo selezionando il controller di visualizzazione nello storyboard, quindi Editor-> Incorpora in-> Navigation Controller.

Nel vostro indexDidChangeForSegmentedControl: metodo si spinge semplicemente il controller della vista che corrisponde alla pila di navigazione:

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

} 

Ma il vostro approccio rende non troppo senso a tutti quando si utilizza storyboard. Non so se è possibile collegare un singolo pulsante di controllo segmentato a un controller di visualizzazione utilizzando segues. Provalo.

8

È la soluzione di Matthias Bauch, ma ho pensato di condividerlo in Swift comunque! Modifica: Aggiunta di un collegamento a un'applicazione dimostrativa ready made di 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

Grazie mille! Questo ha reso la mia giornata :) – AlexB

+0

Certo, è un piacere :) – Abdurrahman

2

Per qualcuno desidera implementare lo stesso in rapida

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! 
    } 
} 

Storyboard

enter image description here

2

A è radice controller di vista, e B, C è sub controller della vista . Quando si fa clic sul segmento, aggiungere il controller della vista secondaria.

risultato

result

disegno

design

codice

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() 
    } 
}