Switch the sub viewController use segmented control - ios

I want switch the sub view controller from the segment control.
There is vc1 and vc2 in the storyboard, and there is segment control on the main vc's navigation controller bar.
I want to add the vc1 and vc2 on the main vc, how to switch the sub vc use the segment controller?
How to do with that?

Follow below steps.
Add VC1 & VC2 as a childVC of mainVC.
On segment 1 selection VC1.view.hidden = false & vc2.view.hidden = true
On segment 2 selection VC2.view.hidden = false & vc1.view.hidden = true
take reference
How-to-add-childVC
How-tobind-segment-control-action
Code work
#IBAction func indexChanged(_ sender: AnyObject) {
switch segmentedControl.selectedSegmentIndex
{
case 0:
vc1.view.hidden = false
vc2.view.hidden = true
case 1:
vc2.view.hidden = false
vc1.view.hidden = true
default:
break
}
}

The accepted answer is obviously correct, but I honestly prefer using container view for each tab in UISegmentedControl. It that way the logic related with each view is separated in different view controller. You can achieve this in that way:
class TopViewController: UIViewController {
#IBOutlet weak var firstContainerView: UIView!
#IBOutlet weak var secondContainerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
firstContainerView.alpha = 1.0
secondContainerView.alpha = 0.0
}
#IBAction func didChangeIndex(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
firstContainerView.alpha = 1.0
secondContainerView.alpha = 0.0
case 1:
firstContainerView.alpha = 0.0
secondContainerView.alpha = 1.0
default:
break
}
}
}
If you would like to access properties of FirstViewController or SecondViewController, you can implement prepare(for segue: UIStoryboardSegue, sender: Any?) method.

You should add vc, and the vc.view to the Main ViewController:
When you select the Segmented Control, you can hide the sub viewcontroller's view like below:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
_vc1 = [sb instantiateViewControllerWithIdentifier:#"ViewController1"];
_vc2 = [sb instantiateViewControllerWithIdentifier:#"ViewController2"];
[self addChildViewController:_vc1];
[self addChildViewController:_vc2];
[self.view addSubview:_vc1.view];
[self.view addSubview:_vc2.view];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)segAction:(UISegmentedControl *)sender {
if (1 == sender.selectedSegmentIndex) {
NSLog(#"1");
_vc1.view.hidden = YES;
_vc2.view.hidden = NO;
}else {
NSLog(#"%ld", sender.selectedSegmentIndex);
_vc2.view.hidden = YES;
_vc1.view.hidden = NO;
}
}

Related

Pass data to TabBar Controller

I want pass data between two ViewControllers throw the TabBarController.
Inside the first ViewController I located textField and button.
Inside the second I located Label.
When I write some text in textField and push button, I expect that this text appear in the Label in the second ViewController. But nothing happens.
And my code:
First ViewController:
import UIKit
class FirstViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
#IBAction func enter(_ sender: Any) {
if textField.text != "" {
if let window = UIApplication.shared.delegate?.window, let tabBarController = window?.rootViewController as? UITabBarController, let second = tabBarController.viewControllers?.first as? SecondViewController {
second.label.text = textField.text
tabBarController.selectedIndex = 0
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Second ViewController:
import UIKit
class SecondViewController: UIViewController {
#IBOutlet weak var label: UILabel!
var myString = String()
override func viewDidLoad() {
super.viewDidLoad()
label.text = myString
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I think the problem is in
tabBarController.viewControllers?.first as? SecondViewController
You probably want to do this instead:
tabBarController.viewControllers?[1] as? SecondViewController
Don't forget arrays are indexed from 0, so viewControllers?[1] actually returns the second element in the array.
I'm not recommending that you do it this way. This is an explanation for understanding.
The viewControllers in a tabBarController know their tabBarController. You can access it with self.tabBarController.
The secondViewController is the second one in the list of viewControllers so let second = tabBarController.viewControllers?[1] as? SecondViewController.
If you haven't visited the secondViewController yet, its view will not have loaded, so the outlets will still be nil. You can force the view to load with _ = second.view.
If you want to switch to the second tab, then you need to use tabBarController.selectedIndex = 1.
#IBAction func enter(_ sender: Any) {
if textField.text != "" {
if let tabBarController = self.tabBarController as? UITabBarController, let second = tabBarController.viewControllers?[1] as? SecondViewController {
// make sure view has loaded
_ = second.view
second.label.text = textField.text
// change to second tab
tabBarController.selectedIndex = 1
}
}
}
A better way...
Instead of setting the outlet directly, you should instead pass the string to a property of the SecondViewController:
second.myString = textField.text ?? ""
and then assign that string to the label in an override of viewWillAppear.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
label.text = myString
}
The reason to set it in viewWillAppear is that viewWillAppear will run every time before the view is displayed. viewDidLoad will only run once when the view is first loaded. Since you want the functionality to work multiple times, viewWillAppear is the correct override.
First i think your view controllers that are representing tabs should be embedded into navigation controllers which would then be linked to the TabBarController.
Secondly, the preferred and recommended way to send data between controllers is through protocols (delegates). Here is a good example you can check out, step by step: https://medium.com/#jamesrochabrun/implementing-delegates-in-swift-step-by-step-d3211cbac3ef
However if you're looking for a quick fix of your solution i think that Bruno Phillipe's answer gets it to some extent, but not quite. We can't really be sure what controller is at what index in the view controller list. I think this should work:
#IBAction func enter(_ sender: Any) {
if textField.text != "" {
if let window = UIApplication.shared.delegate?.window, let tabBarController = window?.rootViewController as? UITabBarController {
//check if there are view controllers in the tabBarController
guard let vcList = tabBarController.viewControllers else {
return
}
for controller in vcList {
if let second = controller as? SecondViewController {
//this will be executed only when a controller is SeconfViewController
second.label.text = textField.text
tabBarController.selectedIndex = 0
}
}
}
}
}
EDIT:
I tried it myself and the problem is that you were trying to set the label.text when in fact the label component was never initialised. I think if you simply stored the textField value into myString variable in SecondViewController it would work (not sure).
However here's the solution using a protocol (delegate) which is the right way to send data between controllers. Ask any questions you might have. This should work:
FirstViewController:
import Foundation
import UIKit
protocol LabelChangeDelegate: class {
func changeLabelWithText(_ text: String?)
}
class FirstViewController: UIViewController {
weak var delegate: LabelChangeDelegate?
#IBOutlet weak var textField: UITextField!
#IBAction func enter(_ sender: UIButton) {
if textField.text != "" {
if let window = UIApplication.shared.delegate?.window, let tabBarController = window?.rootViewController as? UITabBarController {
//check if there are view controllers in the tabBarController
guard let vcList = tabBarController.viewControllers else {
return
}
for controller in vcList {
if let second = controller as? SecondViewController {
//this will be executed only when a controller is SeconfViewController
//set the delegate - who needs the data
delegate = second
//call the delegate function which will commmunicate with the delegate
delegate?.changeLabelWithText(textField.text!)
//don't know why you need this
tabBarController.selectedIndex = 0
}
}
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
SecondViewController:
import Foundation
import UIKit
class SecondViewController: UIViewController, LabelChangeDelegate {
#IBOutlet weak var label: UILabel!
//lazy init
lazy var myString = String()
override func viewDidLoad() {
super.viewDidLoad()
//set label when the view loads, not in the first controller
label.text = myString
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//delegate function
func changeLabelWithText(_ text: String?) {
guard let sentText = text else {
//no text sent
return
}
myString = sentText
}
}

Open UIViewController upon clicking on UITabbarItem

I have created a UIViewController with a UITabbar in it.
I did not use UITabbarController because I wanted UITabbar on the top of the screen.
Upon clicking tab1, I want to present controller1 and on clicking tab2 I want to present controller 2. I don't want the tabbar to hide. I want to display the controller beneath the tabbar.
#interface MTLeaderFactoViewController () <UITabBarDelegate>
#property (weak, nonatomic) IBOutlet UITabBar *tabBar;
#end
#implementation MTLeaderFactoViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
if (item.tag == 0) {
NSLog(#"item tag 0");
} else {
NSLog(#"item tag 1");
}
}
#end
My questions:
1) didSelectItem method is not triggered even after using UITabbarDelegate
2) What is the most elegant way of displaying the controller when clicked on a button? I don't want to use segue as all the controllers are in different storyboards.
For now, I plan to do
Controller1 *fp = [Controller1 controllerStoryboard:STORYBOARD_COURSE];
[self addChildViewController:fp];
[self.view addSubview:fp.view];
[fp didMoveToParentViewController:self];
EDIT 1:
Controller1 *fp = [Controller1 controllerStoryboard:STORYBOARD_COURSE];
[self addChildViewController:fp];
[self.view addSubview:fp.view];
[fp didMoveToParentViewController:self];
Tried this but it hides the tab bar. I want to utilize the space beneath the tab bar to display the controller
What you need to do is have a basecontroller class which will contain a tabbar(programatically created) then you can achive the desired output heres a sample baseController that i created,
import UIKit
class BaseViewController: UIViewController,UITabBarDelegate{
override func viewDidLoad() {
super.viewDidLoad()
let myTabBar = UITabBar()
myTabBar.frame = CGRect(x: 0, y: 60, width:self.view.frame.size.width, height: 50)
let one = UITabBarItem()
one.title = "one"
one.tag = 1
let two = UITabBarItem()
two.title = "two"
two.tag = 2
myTabBar.setItems([one,two], animated: false)
self.view.addSubview(myTabBar)
myTabBar.delegate = self
}
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
switch item.tag {
case 1:
let controller = storyboard?.instantiateViewController(withIdentifier: "SecondViewController")
addChildViewController(controller!)
view.addSubview((controller?.view)!)
controller?.didMove(toParentViewController: self)
break
case 2:
let controller = storyboard?.instantiateViewController(withIdentifier: "ViewController")
addChildViewController(controller!)
view.addSubview((controller?.view)!)
controller?.didMove(toParentViewController: self)
break
default:
break
}
}
}
View Controller class :
import UIKit
class ViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
SecondView Controller :
import UIKit
class SecondViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
I would suggest using UITabBarController instead of UIViewController.
Add UITabViewController in your StoryBoard name it FirstTabBarController.
Add child view controller to FirstTabBarController. In all your child view of add UITabbar. Connect the TabBar delegate to each of your child ViewController.
Hide the default TabBar in your default FirstTabBarController.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.tabBar.isHidden = true;
[self setSelectedIndex:1];
}
Add action to TabBar in your child ViewController as
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
NSUInteger index = [[theTabBar items] indexOfObject:item];
NSLog(#"Tab index = %u", (int)indexO);
[self.navigationController.tabBarController setSelectedIndex:index];
}
I would prefer this method over manually adding adding or removing ViewController as subview, let the UITabBarController manage that for you. Do let me know if you have further queries.

Programmatically switch view controller to show views in Tab Bar Controller

I am trying to figure out how I can programmatically switch the views from one view controller to a first view controller in a Tab bar controller when I press a button.
Currently I have a view controller with three buttons. When I press a button I would like to then switch. This is the following code I have for this screen. It is called the second view controller.
import UIKit
class SecondViewController: UIViewController {
//Button Outlets
#IBOutlet var ButtonEndOfShift: UIButton!
#IBOutlet var ButtonMultiTimes: UIButton!
#IBOutlet var ButtonEndAndLunch: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//hides tab bar controller
self.tabBarController?.tabBar.hidden = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Changes screen for End Of Shift Button
#IBAction func ChangeNextViewLow(sender: AnyObject) {
self.performSegueWithIdentifier("segue", sender: nil)
}
//Changes screen for Lunch and End Of Shift Button
#IBAction func ChangeNextViewMedium(sender: UIButton) {
}
//Changes screen for Multiple Times button
#IBAction func ChangeNextViewHigh(sender: UIButton) {
}
}
I have added UITabBarController in Storyboard like below please see images.
Then i have written following functions for your help.
// For navigate to Tabbar Controller
#IBAction func btnClick () {
self.performSegueWithIdentifier("GoToTabBar", sender: nil)
}
// For switching between tabs
func switchTab (index : Int) {
self.tabbarController.selectedIndex = index
}
You can also set UITabBarController as your application RootViewController.
Implement Code For didFinishLaunchingWithOptions
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
firstViewController *firstTab = [[firstViewController alloc] initWithNibName:#"firstViewController" bundle:nil];
UINavigationController *navCntrl1 = [[UINavigationController alloc] initWithRootViewController:firstTab];
secViewController *secTab = [[firstViewController alloc] initWithNibName:#"secViewController" bundle:nil];
UINavigationController *navCntrl2 = [[UINavigationController alloc] initWithRootViewController:secTab];
thirdViewController *thirdTab = [[thirdViewController alloc] initWithNibName:#"thirdViewController" bundle:nil];
UINavigationController *navCntrl3 = [[UINavigationController alloc] initWithRootViewController:thirdTab];
UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = #[navCntrl1, navCntrl2, navCntrl3];
[self.window setRootViewController:tabBarController];
[self.window makeKeyAndVisible];

How to make UIImage navigate to another ViewController?

Is it possible to make UIImage navigate to another ViewController when I tap on it ?
Just like UIButton.
Thanks.
ya you can use
var tap = UITapGestureRecognizer(target: self, action: Selector("imageCliecked"))
yourimageView.addGestureRecognizer(tap)
yourimageView.userInteractionEnabled = true // this is must dont forget to add
method is
func imageCliecked()
{
println("Tapped on Image")
// navigate to another
self.performSegueWithIdentifier("yoursegueName", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender:AnyObject?)
{
if segue.identifier == "yoursegueName" {
var destViewController: ViewController = segue.destinationViewController as ViewController
destViewController.img = imageView.image // pass your imageview
}
}
another ViewController
class ViewController: UIViewController
{
strong var img: UIImage!
override function viewDidLoad()
{
if(self.img)
self.imageView.image = img;
}
}
UIImageView *imageView=[[UIImageView alloc]init];
//add gesture recogniser
UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(navigate)];
tap.delegate=self;
[imageView addGestureRecognizer:tap];
//call method
-(void)navigate{
//call the navigation ..
}
For your question I have tried below solution.Also it works fine.
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var tapGesture = UITapGestureRecognizer(target: self, action: "navigationFromImage:")
tapGesture.numberOfTapsRequired = 1
imageviewNavigation.userInteractionEnabled = true
imageviewNavigation.addGestureRecognizer(tapGesture)
}
func navigationFromImage(sender: UIGestureRecognizer)
{
var secondViewController = storyboard?.instantiateViewControllerWithIdentifier("navigatingSecondViewController") as SecondViewController
secondViewController.globalImage = imageviewNavigation.image!
navigationController?.pushViewController(secondViewController, animated: true)
//OR
presentViewController(secondViewController, animated: true, completion: nil)
}
Also in Storyboard click the required view controller
1.Go to or click show the Identity inspector
2.Click Identity
3.In StorybordId you must give "navigatingSecondViewController" or whatever you want.
4.Finally you must give same name in your storyboard?.instantiateViewControllerWithIdentifier("navigatingSecondViewController")
in SecondViewController
var globalImage: UIImage = UIImage()
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
imageAccess.image = globalImage
}
yes it is possible to navigate one controller to another controller using property...
e.g.
// second Controller.....(you pass image on this controller)
#import <UIKit/UIKit.h>
#interface NewScreen : UITableViewController
{
}
#property(strong,nonatomic)UIImage *yourImage;
#end
/// First Controller where you pass your image...
- (IBAction)convertVideoButtonClicked:(id)sender
{
NewScreen *objNew=[self.storyboard instantiateViewControllerWithIdentifier:#"NewScreen"];
objNew.yourImage=imageNamed;
[self.navigationController pushViewController:objNew animated:YES];
// NSURL *videoPath = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"part1" ofType:#"mov"]];
// [self convertVideoToMP4:videoPath];
}

Switching ViewControllers with UISegmentedControl in iOS5

I am trying something very simple but somehow I can't get it to work. All I try to do is switching between 2 View Controllers using an UISegmentedControl as you can see it for example in the App Store application in the Highlights tab.
I am using iOS5 and Storyboards.
Here's my Storyboad line up:
So I have a root View Controller and two UITableViews - This 2 TableViews I want to switch.
Here's how the implementation file looks like
#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
I can trigger the switch event and can log the currently selected index. But I don't have any idea where to go from here.
Maybe someone can turn my attention towards a certain direction...?
This code works pretty well for your purpose, I use it for one of my new apps.
It uses the new UIViewController containment APIs that allow UIViewControllers inside your own UIViewControllers without the hassles of manually forwarding stuff like 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;
}
I got this stuff from chapter 22 of Ray Wenderlichs book iOS5 by tutorial.
Unfortunately I don't have a public link to a tutorial. But there is a WWDC 2011 video titled "Implementing UIViewController Containment"
EDIT
self.typeSegmentedControl is outlet for your UISegmentedControl
self.contentView is outlet for your container view
self.currentViewController is just a property that we're using to store our currently used UIViewController
It's Matthias Bauch solution, but thought of sharing it in Swift anyway!
Edit:
Adding a link to a Swift 2.0 ready made demo app.
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
}
For someone want to implement the same in 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!
}
}
Storyboard view
A is root view controller, and B, C is sub view controller.
When you click segment, add sub view controller.
result
design
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()
}
}
You could embed your initial view controller in a navigation controller. Do that by selecting the view controller in the storyboard, then Editor->Embed in->Navigation Controller.
In your indexDidChangeForSegmentedControl: method you simply push the corresponding view controller to the navigation stack:
- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl*)segmentedControl
{
[self.navigationController pushViewController:[self.viewControllers objectAtIndex:[segmentedControl.selectedIndex]] animated:YES];
}
But your approach makes not too much sense at all when you are using storyboards.
I don't know whether you can wire up a single segmented control button to a view controller using segues. Just try it.
I ended up using a navigation controller to achieve a similar functionality.
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
}
}
}

Resources