how - Conmutación de ViewControllers con UISegmentedControl en iOS5
swift 4 segmented control example (5)
¡Es la solución de Matthias Bauch, pero de todos modos pensé en compartirla en Swift! Editar: Agregar un enlace a una aplicación de demostración preparada para 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
}
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.
Estoy usando iOS5 y Storyboards.
Aquí está mi alineación de Storyboad:
Así que tengo un controlador de vista raíz y dos UITableViews: estas 2 TableViews quiero cambiar.
Así es como se ve el archivo de implementación
#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 de cambio y puedo registrar el índice seleccionado actualmente. Pero no tengo idea de dónde ir desde aquí.
¿Tal vez alguien pueda dirigir mi atención hacia una determinada dirección ...?
A es controlador de vista raíz y B, C es controlador de vista secundaria. Al hacer clic en segmento, agregue el controlador de subvista.
resultado
diseño
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()
}
}
Este código funciona bastante bien para su propósito, lo uso para una de mis nuevas aplicaciones.
Utiliza las nuevas API de contención UIViewController que permiten UIViewControllers dentro de sus propios UIViewControllers sin las molestias de reenviar manualmente cosas 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;
}
Obtuve este material del capítulo 22 del libro de Ray Wenderlichs iOS5 por tutorial . Lamentablemente, no tengo un enlace público a un tutorial. Pero hay un video de la WWDC 2011 titulado "Implementación de la contención de UIViewController"
EDITAR
self.typeSegmentedControl
es la salida para su UISegmentedControl
self.contentView
es una salida para su vista de contenedor
self.currentViewController
es solo una propiedad que estamos usando para almacenar nuestro UIViewController
utilizado actualmente
Para alguien quiere implementar lo mismo en forma rápida
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 del guión gráfico
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 método indexDidChangeForSegmentedControl: simplemente inserta el controlador de vista correspondiente en la pila de navegación:
- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl*)segmentedControl
{
[self.navigationController pushViewController:[self.viewControllers objectAtIndex:[segmentedControl.selectedIndex]] animated:YES];
}
Pero su enfoque no tiene demasiado sentido cuando está usando storyboards. No sé si puede cablear un solo botón de control segmentado a un controlador de visualización usando los segmentos. Solo inténtalo.