Basculer ViewControllers avec UISegmentedControl dans iOS5

J'essaie quelque chose de très simple mais je n'arrive pas à le faire fonctionner. Tout ce que j'essaie de faire est de basculer entre 2 controllers de vue en utilisant un UISegmentedControl comme vous pouvez le voir par exemple dans l'application App Store dans l'onglet Faits saillants.

J'utilise iOS5 et Storyboards.

Voici ma gamme Storyboad:

entrez la description de l'image ici

J'ai donc un controller View racine et deux UITableViews – Ce 2 TableViews je veux passer.

Voici à quoi ressemble le file d'implémentation

#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 

Je peux triggersr l'événement switch et save l'index actuellement sélectionné. Mais je n'ai aucune idée d'où aller à partir d'ici.

Peut-être que quelqu'un peut tourner mon attention vers une certaine direction …?

Ce code fonctionne assez bien pour votre usage, je l'utilise pour l'une de mes nouvelles applications.
Il utilise les nouvelles API de confinement UIViewController qui autorisent les UIViewControllers à l'intérieur de vos propres UIViewControllers sans les tracas d'un transfert manuel de choses comme 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; } 

J'ai obtenu ce truc du chapitre 22 du livre de Ray Wenderlichs iOS5 par tutoriel . Malheureusement, je n'ai pas de lien public vers un tutoriel. Mais il existe une video de la WWDC 2011 intitulée "Implémentation du confinement UIViewController"

MODIFIER

self.typeSegmentedControl est la sortie de votre UISegmentedControl

self.contentView est la sortie pour votre vue de conteneur

self.currentViewController est juste une propriété que nous utilisons pour stocker notre UIViewController actuellement utilisé

C'est la solution de Matthias Bauch, mais j'ai pensé à la partager avec Swift de toute façon! Modifier: Ajouter un lien vers une application de démonstration prête à l'emploi 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 } 

Pour quelqu'un veut mettre en œuvre la même chose dans 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! } } 

Vue de Storyboard

entrez la description de l'image ici

A est le controller de vue racine, et B, C est le controller de sous-vue. Lorsque vous click le segment, ajoutez un controller de vue secondaire.

résultat

résultat

design

conception

code

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

Vous pouvez intégrer votre controller de vue initial dans un controller de navigation. Pour ce faire, select le controller de vue dans le storyboard, puis Editeur-> Intégrer dans> Contrôleur de navigation.

Dans votre méthode indexDidChangeForSegmentedControl: vous poussez simplement le controller de vue correspondant vers la stack de navigation:

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

Mais votre approche n'a pas trop de sens du tout lorsque vous utilisez des storyboards. Je ne sais pas si vous pouvez câbler un seul button de contrôle segmenté à un controller de vue en utilisant des segues. Essayez-le.