38 votes

Changement de ViewControllers avec UISegmentedControl dans iOS5

Je suis en train d'essayer quelque chose de très simple mais d'une manière ou d'une autre je n'arrive pas à le faire fonctionner. Tout ce que j'essaie de faire, c'est de passer entre 2 View Controllers en utilisant un UISegmentedControl comme vous pouvez le voir par exemple dans l'application App Store dans l'onglet Highlights.

Je suis en train d'utiliser iOS5 et les Storyboards.

Voici mon agencement dans Storyboard:

entrez la description de l'image ici

J'ai donc un root View Controller et deux UITableViews - Ces 2 TableViews je veux les changer.

Voici à quoi ressemble le fichier 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];
}

// Mise en œuvre de viewDidLoad pour effectuer des réglages supplémentaires après le chargement de la vue, généralement à partir d'un nib.
- (void)viewDidLoad
{
    [super viewDidLoad();
    [self setupViewControllers();
    [self setupUI();
}

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

Je peux déclencher l'événement de changement et enregistrer l'index actuellement sélectionné. Mais je n'ai aucune idée de où aller à partir de là.

Peut-être que quelqu'un peut m'orienter dans une certaine direction...?

1 votes

Avez-vous pensé à simplement recharger le tableView avec des valeurs différentes?

0 votes

Tu as raison. Je vais vérifier ça maintenant. Je pourrais penser trop compliqué...

83voto

Matthias Bauch Points 52145

Ce code fonctionne très bien pour votre objectif, je l'utilise pour l'une de mes nouvelles applications.
Il utilise les nouvelles API de containment de UIViewController qui permettent d'insérer des UIViewControllers à l'intérieur de vos propres UIViewControllers sans les tracas de transmettre manuellement des choses comme viewDidAppear:

- (void)viewDidLoad {
    [super viewDidLoad];
    // ajouter un viewController pour pouvoir les changer plus tard. 
    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 trouvé ces informations au chapitre 22 du livre de Ray Wenderlich iOS5 by tutorial. Malheureusement, je n'ai pas de lien public vers un tutoriel. Mais il y a une vidéo de la WWDC 2011 intitulée "Implementing UIViewController Containment"

ÉDIT

self.typeSegmentedControl est la sortie pour votre UISegmentedControl

self.contentView est la sortie pour votre vue conteneur

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

0 votes

Je n'ai pas réussi avec les storyboards mais lorsque j'utilise votre code avec les fichiers nib, ça fonctionne... Donc merci, vous avez mon vote ;)

3 votes

Cela déchire mec. Je viens de découvrir [self storyboard] après 2 mois. Merci!!

0 votes

Cela peut sembler être une question stupide, mais lorsque je commence de zéro, j'ai des problèmes comme cette propriété 'typeSegmentedControl' non trouvée sur un objet de type 'ViewController *'. Je dois sûrement faire quelque chose de stupide, n'est-ce pas ?

10voto

Abdurrahman Points 5836

C'est la solution de Matthias Bauch, mais j'ai pensé la partager en Swift quand même! Éditer: Ajout d'un lien vers une application de démonstration prête pour 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
}

4voto

JITHINRAJ Points 6

Pour quelqu'un qui souhaite implémenter la même chose 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!
    }
}

Vue de Storyboard

description de l'image ici

2voto

aotian16 Points 511

A est la vue contrôleur racine, et B, C sont des sous-vues contrôleur. Lorsque vous cliquez sur le segment, ajoutez le sous-vue contrôleur.

résultat

résultat

design

design

code

import UIKit

class SegmentViewController: UIViewController {

    @IBOutlet weak var containerView: UIView!

    var leftViewController: LeftViewController!
    var rightViewController: RightViewController!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Faire toute configuration supplémentaire après le chargement de la vue, généralement à partir d'un 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()
        // Libérer les ressources non utilisées.
        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()
    }
}

0voto

travisluong Points 121

J'ai fini par utiliser un contrôleur de navigation pour obtenir une fonctionnalité similaire.

import UIKit

class BaseViewController: UIViewController {

var currentSegmentIndex = 0

@IBOutlet weak var segmentedControl: UISegmentedControl!

override func viewDidLoad() {
super.viewDidLoad()

segmentedControl.selectedSegmentIndex = currentSegmentIndex
}

@IBAction func segmentedControlChanged(_ sender: Any) {
let idx = segmentedControl.selectedSegmentIndex
let storyboard = UIStoryboard(name: "Main", bundle: nil)
switch idx {
case 0:
let vc = storyboard.instantiateViewController(
withIdentifier: "Foo") as! FooViewController
vc.currentSegmentIndex = 0
navigationController?.viewControllers = [vc]
break
case 1:
let vc = storyboard.instantiateViewController(
withIdentifier: "Bar") as! BarViewController
vc.currentSegmentIndex = 1
navigationController?.viewControllers = [vc]
break
default:
break
}
}
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X