Программное кодирование 2 UISwitches в 1 сцене

Я нахожусь в процессе написания приложения, я использую Xcode 11.3.1/Swift 5 (хотя эта проблема такая же в Xcode 10/Swift 4). Первоначально, когда я начал писать свое приложение, я использовал раскадровку для размещения двух UISwitch в сцене, и идея заключалась в том, что если UISwitch-1 включен, то UISwitch-2 выключен, и наоборот, всякий раз, когда пользователь нажимает на любой из них. Функциональность работает на славу (ну мои методы/код/IBActions и IBOutlets) - все работает.

Однако я хочу программно закодировать UISwitches, а не использовать раскадровку, потому что я хочу иметь возможность размещать переключатели в разных местах по оси Y в зависимости от типа устройства iPhone, т.е. поскольку iPhone 11Pro Max длиннее iPhone 6, я хочу переключить UISwitches вниз. Я не верю, что смогу сделать это в раскадровке, поэтому хочу программно закодировать их.

Проблема не в кодировке переключателей, я их закодировал и они работают. Однако проблема в том, что если я включу UISwitch-1, то не смогу понять код, чтобы выключить UISwitch-2 (и наоборот). Я думаю, что моя ошибка заключается в том, что я не знаю, как вызвать IBOutlet в методах для настройки «другого» переключателя (то есть того, который пользователь не переключал).

Блок кода ниже представляет собой код, связанный с техникой/методом раскадровки с использованием IBActions и 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!

'''

Тем не менее, следующий блок кода - это мой код при попытке программно запрограммировать UISwitches, и, как я уже сказал, код работает в том смысле, что я могу отображать UISwitches, однако, когда я нажимаю на любой из UISwitches, которые я закодировал программно, я не могу получить их для обновления другого UISwitch, который я создал программно....

'''

 // 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)
        }
    }
'''

person James Leitch    schedule 26.02.2020    source источник


Ответы (2)


1. Создайте setSingleMode и setFamilyMode в качестве instance properties ViewController.

2. В displaySwitches() установите их значения как singleUserModeSwitch и familyUserModeSwitch.

3. Измените определения valueChange1(_:) и valueChange2(_:) соответствующим образом.

Вот код, чтобы обобщить вышеперечисленные пункты.

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)
    }
}
person PGDev    schedule 26.02.2020
comment
БЛЕСТЯЩИЙ !! Я последовал вашему совету выше с 1 небольшим дополнением/модификацией, которая заключалась в том, чтобы вставить view.addSubview(singleUserModeSwitch) после строки .addTarget и view.addSubview(familyUserModeSwitch) после другой строки .addTarget, и тогда это работает. Большое вам спасибо - я потратил несколько ночей, пытаясь заставить это работать (я думаю, моя жена хочет подарок за то, что она такая терпеливая), и вы решили мою проблему в кратчайшие сроки. Я бы никогда не смог этого сделать. Спасибо огромное. - person James Leitch; 26.02.2020
comment
@JamesLeitch Отлично. Примите (отметьте слева), если это сработало для вас. Удачного кодирования..???? - person PGDev; 26.02.2020

Сделайте переключатель в коде следующим образом:

lazy var setFamilyMode: UISwitch = {
        let familySwitch = UISwitch()
        familySwitch.translatesAutoresizingMaskIntoConstraints = false
        // switch property settings
        return familySwitch
}()

lazy var setSingleMode: UISwitch = {
    let singleSwitch = UISwitch()
    singleSwitch.translatesAutoresizingMaskIntoConstraints = false
    // switch property settings
    return singleSwitch
}()

Затем добавьте переключатель в представление:

view.addSubView(setFamilyMode)
view.addSubView(setSingleMode)

При необходимости добавьте ограничения или установите рамку для переключателей. Если вы устанавливаете кадр, установите для свойства translatesAutoresizingMaskIntoConstraints переключателей значение true. Сохраните yAxis в соответствии с вашими требованиями и измените в соответствии с вашим кодом.

Не забудьте добавить цель для ваших коммутаторов

setFamilyMode.addTarget(self, action: #selector(valueChange1(_:)), for: .valueChanged)
setSingleMode.addTarget(self, action: #selector(valueChange2(_:)), for: .valueChanged)
person iOS_MIB    schedule 26.02.2020