Swift - Segmented Control - Switch Multiple Views

Swift - Segmented control - Switch multiple views

You can use the isHidden property of the UIView to show/hide your required views.
First you have to link both views to IBOutlets through the Interface builder

@IBOutlet weak var historyView: UIView!
@IBOutlet weak var popularView: UIView!

@IBAction func indexChanged(_ sender: UISegmentedControl) {
switch segmentedControl.selectedSegmentIndex {
case 0:
historyView.isHidden = true
popularView.isHidden = false
case 1:
historyView.isHidden = false
popularView.isHidden = true
default:
break;
}
}

Note: it was named hidden in Swift 1 and 2.

Swift Segmented control Switch multiple views from navigation Title

At first, if you're not using Storyboards/XIBs/InterfaceBuilder and doing everything programmatically, you can remove @IBAction, as it means Interface Builder Action.

Secondly, it is good idea to put segmented control as a variable, so you can access it easier when needed:

var customSC: UISegmentedControl - just after class MyVC: UIViewController {.

But Swift requires all variables to be initialized before calling a superclass designated initializer - init(nibName nibNameOrNil:, so, let's initialize it: it is possible to initialize variables in it's declaration:

Change var customSC: UISegmentedControl to

  var customSC: UISegmentedControl = {
let items = ["Tab 1", "Tab 2", "Tab 3", "Tab 4"]
let control = UISegmentedControl(items: items)
control.selectedSegmentIndex = 0
return control
}()

So, we don't need to configure Segmented Control in viewDidLoad method.

The problem, why you your control wasn't working is that you haven't added target to it. So, when you change selected segment, the control does not sends any events to your viewcontroller. Let's fix it. Add this method to the end of viewDidLoad:

customSC.addTarget(self, action: "indexChanged:", forControlEvents: UIControlEvents.ValueChanged)
Now, when you press any of the segments, the method indexChanged(sender: UISegmentedControl) will be called and the view controller will be able to react.

It would be easier to put segmented control on top of navigation bar this way: navigationItem.titleView = customSC, it is much shorter than this: navigationController?.navigationBar.topItem?.titleView = customSC

When using Interface Builder it is OK to use weak modifiers for WebView as it is being automatically added to the main view of the controller and being held in memory. But if you add it programmatically, you should avoid using weak in this context in order to prevent undesired behavior (Web View will be deallocated as soon as there are no strong (i.e. not weak) links to it, so basically, it will be deallocated immediately after creation and you end up with BAD ACCESS error. To fix it, just change this: weak var webView: UIWebView! to this var webView: UIWebView!.

So, after small refactoring, we may finish with something close to this:

import UIKit
class MyVC: UIViewController {

var webviewURL: NSURL = NSURL(string: "myURL")!
var webviewURL2: NSURL = NSURL(string: "myURL")!
var webviewURL3: NSURL = NSURL(string: "myURL")!
var webviewURL4: NSURL = NSURL(string: "myURL")!

var webView: UIWebView!

var customSC: UISegmentedControl = {
let items = ["Tab 1", "Tab 2", "Tab 3", "Tab 4"]
let control = UISegmentedControl(items: items)
control.selectedSegmentIndex = 0
return control
}()

func indexChanged(sender: UISegmentedControl) {
switch customSC.selectedSegmentIndex { //error here
case 0:
let requestObj = NSURLRequest(URL: webviewURL)
webView.loadRequest(requestObj)
case 1:
let requestObj = NSURLRequest(URL: webviewURL2)
webView.loadRequest(requestObj)
case 2:
let requestObj = NSURLRequest(URL: webviewURL3)
webView.loadRequest(requestObj)
case 3:
let requestObj = NSURLRequest(URL: webviewURL4)
webView.loadRequest(requestObj)
default:
break;
}
}

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: "myVC", bundle: nil)
}

convenience init() {
self.init(nibName: "myVC", bundle: nil)
//set the tab bar item's title
tabBarItem.title = "title"

//put an image on the tab bar item
tabBarItem.image = UIImage(named: "image")
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
super.viewDidLoad()

let logo = UIImage(named: "image")
let logoView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 80))
logoView.contentMode = .ScaleAspectFit
logoView.image = logo
let leftLogo = UIBarButtonItem(customView: logoView)
self.navigationItem.leftBarButtonItem = leftLogo

navigationItem.titleView = customSC
navigationController?.navigationBar.translucent = false

let requestObj = NSURLRequest(URL: webviewURL)
webView.loadRequest(requestObj)
}
}

Switch between tableViews using segmented Control

Use an enum to know what to display in your tab depending on segment control value :

enum DispkayedTasks {
case current
case past
}
var displayedTask = DisplayedTasks.current

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch (displayedTask) {
case .current:
// First segment tapped
return self.tasks.count
case .past:
// Second segment tapped
return self.pastTasks.count
}
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! MyTasksTableCell
cell.accessoryType = .disclosureIndicator
let task = {() -> Add in
switch (displayedTask) {
case .current:
// First segment tapped
return self.tasks[indexPath.row]
case past:
// Second segment tapped
return self.pastTasks[indexPath.row]
}
}()

cell.categoryLabel.text =
"\(task.category)"
cell.dateLabel.text =
"\(task.date)"
cell.hourLabel.text =
"\(task.hour)"

if cell.categoryLabel.text == "Urgent" {
cell.categoryIcon.image = #imageLiteral(resourceName: "red.png")
}
if cell.categoryLabel.text == "Important" {
cell.categoryIcon.image = #imageLiteral(resourceName: "orange.png")
}
if cell.categoryLabel.text == "Not Important" {
cell.categoryIcon.image = #imageLiteral(resourceName: "green.png")
}
cell.dateIcon.image = UIImage(systemName: "calendar.badge.clock")

return cell

}

@objc func segmentControl(_ segmentedControl: UISegmentedControl) {
switch (segmentedControl.selectedSegmentIndex) {
case 0:
// First segment tapped
print("Present Tasks")
displayedTasks = .current
self.tableView.reloadData()

case 1:
// Second segment tapped
print("Past Tasks")
displayedTasks = .past

self.tableView.reloadData()

default:
break
}
}

Segmented control to switch collection views

You create a different instance each line

addChild(FirstCVC())
addChild(SecondCVC())
addChild(ThirdCVC())
addChild(FourthCVC())

self.view.addSubview(FirstCVC().view)
self.view.addSubview(SecondCVC().view)
self.view.addSubview(ThirdCVC().view)
self.view.addSubview(FourthCVC().view)

FirstCVC().didMove(toParent: self)
SecondCVC().didMove(toParent: self)
ThirdCVC().didMove(toParent: self)
FourthCVC().didMove(toParent: self)

FirstCVC().view.frame = self.view.bounds
SecondCVC().view.frame = self.view.bounds
ThirdCVC().view.frame = self.view.bounds
FourthCVC().view.frame = self.view.bounds

while it should be

let vc1 = FirstCVC()

let vc2 = SecondCVC()

let vc3 = ThirdCVC()

let vc4 = FourthCVC()

addChild(vc1)
addChild(vc2)
addChild(vc3)
addChild(vc4)

self.view.addSubview(vc1.view)
self.view.addSubview(vc2.view)
self.view.addSubview(vc3.view)
self.view.addSubview(vc4.view)

vc1.didMove(toParent: self)
vc2.didMove(toParent: self)
vc3.didMove(toParent: self)
vc4.didMove(toParent: self)

vc1.view.frame = self.view.bounds
vc2.view.frame = self.view.bounds
vc3.view.frame = self.view.bounds
vc4.view.frame = self.view.bounds

Tip : Also you better create an extension instead of repeating the 4 lines for each vc

switching views between views in ios using segmented control

Depending on how demanding the content four views is, I would suggest to make one main view for the segmented control and set up four container views in the main view. The three of them should be hidden and then you can toggle between the four views (show/hide).

This is only a good solution if the views' codes are very "soft" or it'll be very slow to run 4-5 views at the same time. If it's four hardcore views I would prefer to use the standard navigation tab bar control instead..

//////// EXAMPLE ////////

The setup will be with one UIViewController for the background. On this view we will place one UISegmentedControl + four container views. The four container views should be placed on the top of each other. The three of the container views are hidden so you only see one.

BackgroundViewController.h:

#import <UIKit/UIKit.h>

@interface BackgroundViewController : UIViewController {
IBOutlet UISegmentedControl *segmentedControl;
UIView actualView;
}

@property (nonatomic, weak) IBOutlet UIView *containerOne;
@property (nonatomic, weak) IBOutlet UIView *containerTwo;
@property (nonatomic, weak) IBOutlet UIView *containerThree;
@property (nonatomic, weak) IBOutlet UIView *containerFour;

@end

Here's an example of the IBAction for the segmented control.

- (void) viewDidLoad {
actualView = self.containerOne;
UIView *fromView = nil;
UIView *toView = nil;

self.containerOne.hidden = NO;
self.containerTwo.hidden = YES;
self.containerThree.hidden = YES;
self.containerFour.hidden = YES;
}

- (IBAction)segmentSwitchClick {
NSInteger selectedSegment = segmentedControl.selectedSegmentIndex;

UIView *fromView = actualView;
UIView *toView = nil;

switch (selectedSegment) {
case 0: {
toView = [self containerOne];
break;
}
case 1: {
toView = [self containerTwo];
break;
}
case 2: {
toView = [self containerThree];
break;
}
case 3: {
toView = [self containerFour];
break;
}
default:
break;
}
}
[UIView transitionFromView:fromView toView:toView duration:1.9 options:UIViewAnimationOptionShowHideTransitionViews | UIViewAnimationOptionCurveLinear
completion:^(BOOL finished) {
if (finished) {
actualView = toView;
}
}];

}

PS I haven't tried it, but it should work.

How do I use a UISegmentedControl to switch views?

The simplest approach is to have two views that you can toggle their visibility to indicate which view has been selected. Here is some sample code on how it can be done, definitely not an optimized way to handle the views but just to demonstrate how you can use the UISegmentControl to toggle the visible view:



- (IBAction)segmentSwitch:(id)sender {
UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
NSInteger selectedSegment = segmentedControl.selectedSegmentIndex;

if (selectedSegment == 0) {
//toggle the correct view to be visible
[firstView setHidden:NO];
[secondView setHidden:YES];
}
else{
//toggle the correct view to be visible
[firstView setHidden:YES];
[secondView setHidden:NO];
}
}



You can of course further re-factor the code to hide/show the right view.

iOS Swift Segmented control with container view for switching - views are not loading first time

You can try added this code after method viewDidLoad, for show animation after app loaded.

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

UIView.animateWithDuration(0.5, animations: {
self.containerViewA.alpha = 1
self.containerViewB.alpha = 0
}
}

Switch the sub viewController use segmented control

Follow below steps.

  1. Add VC1 & VC2 as a childVC of mainVC.

  2. On segment 1 selection VC1.view.hidden = false & vc2.view.hidden = true

  3. On segment 2 selection VC2.view.hidden = false & vc1.view.hidden = true

take reference

  1. How-to-add-childVC

  2. 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
}
}

Change views using Segmented Control

Here i have created a complete solution as per your requirement.

Swift 4

//
// SegementedVC.swift
//
// Created by Test User on 01/02/18.
// Copyright © 2018 Test User. All rights reserved.
//

import UIKit

class SegementedVC: UIViewController {

//----------------------------------------------------------------
// MARK:-
// MARK:- Outlets
//----------------------------------------------------------------

@IBOutlet weak var segmentControl : UISegmentedControl!
@IBOutlet weak var containerView : UIView!

//----------------------------------------------------------------
// MARK:-
// MARK:- Variables
//----------------------------------------------------------------

private lazy var firstViewController: FirstViewController = {
// Load Storyboard
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)

// Instantiate View Controller
var viewController = storyboard.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController

// Add View Controller as Child View Controller
self.add(asChildViewController: viewController)

return viewController
}()

private lazy var secondViewController: SecondViewController = {
// Load Storyboard
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)

// Instantiate View Controller
var viewController = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController

// Add View Controller as Child View Controller
self.add(asChildViewController: viewController)

return viewController
}()

//----------------------------------------------------------------
// MARK:-
// MARK:- Abstract Method
//----------------------------------------------------------------

static func viewController() -> SegementedVC {
return UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SegementedView") as! SegementedVC
}

//----------------------------------------------------------------
// MARK:-
// MARK:- Memory Management Methods
//----------------------------------------------------------------

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}

//----------------------------------------------------------------
// MARK:-
// MARK:- Action Methods
//----------------------------------------------------------------

@IBAction func segmentValueChanged(_ sender: UISegmentedControl) {
updateView()
}

//----------------------------------------------------------------
// MARK:-
// MARK:- Custom Methods
//----------------------------------------------------------------

private func add(asChildViewController viewController: UIViewController) {

// Add Child View Controller
addChildViewController(viewController)

// Add Child View as Subview
containerView.addSubview(viewController.view)

// Configure Child View
viewController.view.frame = containerView.bounds
viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]

// Notify Child View Controller
viewController.didMove(toParentViewController: self)
}

//----------------------------------------------------------------

private func remove(asChildViewController viewController: UIViewController) {
// Notify Child View Controller
viewController.willMove(toParentViewController: nil)

// Remove Child View From Superview
viewController.view.removeFromSuperview()

// Notify Child View Controller
viewController.removeFromParentViewController()
}

//----------------------------------------------------------------

private func updateView() {
if segmentControl.selectedSegmentIndex == 0 {
remove(asChildViewController: secondViewController)
add(asChildViewController: firstViewController)
} else {
remove(asChildViewController: firstViewController)
add(asChildViewController: secondViewController)
}
}

//----------------------------------------------------------------

func setupView() {
updateView()
}

//----------------------------------------------------------------
// MARK:-
// MARK:- View Life Cycle Methods
//----------------------------------------------------------------

override func viewDidLoad() {
super.viewDidLoad()
self.setupView()
}

//----------------------------------------------------------------

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}

//----------------------------------------------------------------

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
}

Storyboard Screenshots

Sample Image

Sample Image

Sample Image



Related Topics



Leave a reply



Submit