I am in the process of writing an app, I am using Xcode 11.3.1 / Swift 5 (although this issue is the same in Xcode 10/Swift 4). Originally when I started writing my app I used the storyboard to place the two UISwitches within the scene and the idea being that if UISwitch-1 is on, then UISwitch-2 is off and vice versa whenever a user clicks on either of them. The functionality works a treat (well my methods/code/IBActions and IBOutlets) - all is working.
However, I want to programmatically code the UISwitches rather than using storyboard because I want to be able to place the switches at different places on the y-axis depending on the iPhone device type, ie. because an iPhone 11Pro Max is longer than an iPhone 6 then I want to shift the UISwitches down. I don't believe I can do this in the storyboard, hence wanting to programmatically code them.
The issue isn't the coding of the switches, I have coded them and they work. However the issue is if I turn UISwitch-1 on then I can't seem to fathom out the code to turn UISwitch-2 off (and vice versa). I think where I am failing is that I don't know how to call the IBOutlet within the methods to adjust the 'other' switch (ie. the one the user didn't toggle).
The code block below is the code associated with the storyboard technique/method using IBActions and IBOutlets:
'''
// MARK: My UISwitches - toggle between the two UISwitches
@IBAction func singleUserModeSwitch(_ sender: UISwitch) {
if dontAllowEditing == false {
if (sender.isOn) == true {
setFamilyMode.setOn(false, animated: true)
} else {
setFamilyMode.setOn(true, animated: false)
}
} else {
myAlertNoDriverProfile()
}
}
@IBOutlet weak var setFamilyMode: UISwitch!
@IBAction func familyUserModeSwitch(_ sender: UISwitch) {
if dontAllowEditing == false {
if (sender.isOn) == true {
setSingleMode.setOn(false, animated: true)
} else {
setSingleMode.setOn(true, animated: false)
}
} else {
myAlertNoDriverProfile()
}
}
@IBOutlet weak var setSingleMode: UISwitch!
'''
However, the next code block is my code when trying to programmatically program the UISwitches and as I say the code works in that I can display the UISwitches, however when I click on either of the UISwitches that I coded programmatically then I am unable to get them to update the other UISwitch that I created programmatically....
'''
// MARK: Display Switch Buttons
func displaySwitches() {
// Determine device type
if DeviceType.isiPhone6 || DeviceType.isiPhoneX {
singleUserModeSwitchPositionY = 484
familyUserModeSwitchPositionY = 525
}
if DeviceType.isiPhone6Plus || DeviceType.isiPhoneXs {
singleUserModeSwitchPositionY = 504
familyUserModeSwitchPositionY = 545
}
// Display UISwitch-1
let singleUserModeSwitch = UISwitch(frame:CGRect(x: 220, y:singleUserModeSwitchPositionY, width: 0, height:0))
singleUserModeSwitch.isOn = true
singleUserModeSwitch.thumbTintColor = UIColor.white
singleUserModeSwitch.tintColor = Colors.jamesBlue
singleUserModeSwitch.onTintColor = Colors.jamesBlue
singleUserModeSwitch.setOn(false, animated: true)
singleUserModeSwitch.addTarget(self, action: #selector(valueChange1), for:UIControl.Event.valueChanged)
view.addSubview(singleUserModeSwitch)
// Display UISwitch-2
let familyUserModeSwitch = UISwitch(frame:CGRect(x: 220, y:familyUserModeSwitchPositionY, width: 0, height:0))
familyUserModeSwitch.isOn = false
familyUserModeSwitch.thumbTintColor = UIColor.white
familyUserModeSwitch.tintColor = Colors.jamesBlue
familyUserModeSwitch.onTintColor = Colors.jamesBlue
familyUserModeSwitch.setOn(true, animated: true)
familyUserModeSwitch.addTarget(self, action: #selector(valueChange2), for:UIControl.Event.valueChanged)
self.view.addSubview(familyUserModeSwitch)
}
@objc func valueChange1(mySwitch1: UISwitch) {
if mySwitch1.isOn{
print("Switch1 (singleUserModeSwitch) is ON")
// I think the lines below (where I try an call the .setOn function is where the problem is
// as I somehow need to call an IBOULET however I don't have one defined because I am
// programmatically creating the UISwitches
setFamilyMode.setOn(false, animated: true)
} else {
print("Switch1 (singleUserMoeSwitch) is OFF")
setFamilyMode.setOn(true, animated: true)
}
}
@objc func valueChange2(mySwitch2: UISwitch) {
if mySwitch2.isOn{
print("Switch2 (familyUserModeSwitch) is ON")
setSingleMode.setOn(false, animated: true)
} else {
print("Switch1 (singleUserMoeSwitch) is OFF")
setSingleMode.setOn(true, animated: true)
}
}
'''
1. Create setSingleMode
and setFamilyMode
as the instance properties
of the ViewController.
2. In displaySwitches()
set their values as singleUserModeSwitch
and familyUserModeSwitch
3. Modify valueChange1(_:)
and valueChange2(_:)
definitions accordingly.
Here is the code to summarise the above points.
class ViewController: UIViewController {
var setSingleMode: UISwitch?
var setFamilyMode: UISwitch?
func displaySwitches() {
//rest of the code...
let singleUserModeSwitch = UISwitch(frame:CGRect(x: 220, y:singleUserModeSwitchPositionY, width: 0, height:0))
//rest of the code...
singleUserModeSwitch.addTarget(self, action: #selector(valueChange1(_:)), for:UIControl.Event.valueChanged)
self.setSingleMode = singleUserModeSwitch
let familyUserModeSwitch = UISwitch(frame:CGRect(x: 220, y:familyUserModeSwitchPositionY, width: 0, height:0))
//rest of the code...
familyUserModeSwitch.addTarget(self, action: #selector(valueChange2(_:)), for:UIControl.Event.valueChanged)
self.setFamilyMode = familyUserModeSwitch
}
@objc func valueChange1(_ mySwitch1: UISwitch) {
print("Switch1 (singleUserModeSwitch) is \(mySwitch1.isOn ? "ON" : "OFF")")
setFamilyMode?.setOn(!mySwitch1.isOn, animated: true)
}
@objc func valueChange2(_ mySwitch2: UISwitch) {
print("Switch2 (familyUserModeSwitch) is \(mySwitch2.isOn ? "ON" : "OFF")")
setSingleMode?.setOn(!mySwitch2.isOn, animated: true)
}
}