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.
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
}
}
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
Related Topics
How to Force My Keyboard to Be Up on My Program's Start in Swift
How to Intercept Push Notifications for Another App
"Rctbundleurlprovider.H" File Not Found - Appdelegate.M
Drawrect Circle and Animate Size/Color
How to Add Private Key to the Distribution Certificate
Extracting H264 from Cmblockbuffer
Invalid Update: Invalid Number of Items on Uicollectionview
Ios: Change the Height of Uisegmentedcontrol
No Round Rect Button in Xcode 5
Linker Error in Xcode 5 for Libzbar.A
How to Return Value After the Execution of the Block? Swift
Opening a PDF Document When Clicking a Button
Pod Install Displaying Error in Cocoapods Version 1.0.0.Beta.1
Using iOS Gamekit's "Bluetooth Bonjour" with Other Platforms
iOS Certificate Pinning with Swift and Nsurlsession