本文介绍了iOS14:没有UIControl在UIKit Modal ViewController中工作了的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用iOS14.0.1,Swift5.3,Xcode12.0.1,

Using iOS14.0.1, Swift5.3, Xcode12.0.1,

我对这个问题感到绝望:

I am desperate with this problem:

在iOS12和iOS13上,我的应用程序运行良好.

With iOS12 and iOS13, my App was working nicely.

但是现在有了iOS14,没有UIButton,没有UISwitch,没有segue -在我的Modal ViewController中什么也没起作用.

But now with iOS14, no UIButton, no UISwitch, no segue - nothing is working in my Modal ViewController.

我不知道苹果在UIKit中做了什么更改才能发生此问题? !!!!

I have no idea what Apple changed in UIKit for this problem to occur ???? !!!!

请帮助!

我的Modal ViewController如下所示:

My Modal ViewController is presented as follows:

@objc func settingsBtnPressed(_ sender: UIButton) {

    let settingsVC = SettingsViewController()
    settingsVC.backDelegate = self

    let navController = UINavigationController(rootViewController: settingsVC)
    navController.navigationBar.barStyle = .black
    navController.navigationBar.tintColor = .white
    navController.navigationBar.prefersLargeTitles = true
    navController.navigationBar.backgroundColor = UIColor.clear
    navController.presentationController?.delegate = self

    self.present(navController, animated: true)
}

class SettingsViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

    let cellId = "cellID"

    init() {
        let collectionViewFlowLayout = UICollectionViewFlowLayout()
        collectionViewFlowLayout.estimatedItemSize = CGSize(width: UIScreen.main.bounds.width, height: 1)
        super.init(collectionViewLayout: collectionViewFlowLayout)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // ...
        collectionView.register(SettingsCollectionViewCell.self, forCellWithReuseIdentifier: cellId)
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 1
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SettingsCollectionViewCell
        cell.setup(titlesFirstSection: titlesFirstSection, iconsFirstSection: iconsFirstSection, onStatesFirstSection: onStatesFirstSection, )
        return cell
    }
}
class SettingsCollectionViewCell: UICollectionViewCell {

    var SettingsStackView = UIStackView()
    var attries: UICollectionViewLayoutAttributes!
    var myContentHeight: CGFloat = 0.0

    var firstSettingsSectionView: MenuSwitchListSectionView?

    let elementHeight: CGFloat = 44.0
    let separatorLineThickness: CGFloat = 1.0
    let sectionViewBackgroundColor = ImageConverter.UIColorFromRGB(0x2C2C2E, alpha: 1.0)

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setup(titlesFirstSection: [String],
                iconsFirstSection: [UIImage?]?,
             onStatesFirstSection: [Bool]) {

        myContentHeight = UIScreen.main.bounds.height - 120

        initFirstSettingsSectionView(titles: titlesFirstSection, icons: iconsFirstSection, onStates: onStatesFirstSection)

        SettingsStackView = VerticalStackView(arrangedSubviews: [
            UIView(),
            firstSettingsSectionView! as UIView,
            UIView()
        ], spacing: 10.0, alignment: .center )

        contentView.addSubview(SettingsStackView)
        contentView.isUserInteractionEnabled = true

        setConstraints(nrOfItemsFirstSection: titlesFirstSection.count)
    }

    fileprivate func initFirstSettingsSectionView(titles: [String], icons: [UIImage?]?, onStates: [Bool]) {

        firstSettingsSectionView = MenuSwitchListSectionView(frame: .zero,
                                  elementHeight: elementHeight,
                         separatorLineThickness: separatorLineThickness,
                                backgroundColor: sectionViewBackgroundColor,
                                         titles: titles,
                                          icons: icons,
                                       onStates: onStates
        )
        firstSettingsSectionView?.switchMutatedDelegate = self
        firstSettingsSectionView?.assignDelegate()
    }

    fileprivate func setConstraints(nrOfItemsFirstSection: Int) {

        contentView.translatesAutoresizingMaskIntoConstraints = false
        SettingsStackView.translatesAutoresizingMaskIntoConstraints = false
        firstSettingsSectionView?.translatesAutoresizingMaskIntoConstraints = false

        SettingsStackView.anchor(top: safeAreaLayoutGuide.topAnchor, leading: contentView.leadingAnchor, bottom: nil, trailing: contentView.trailingAnchor)

        let totalHeightFirstSection: CGFloat = elementHeight * CGFloat(nrOfItemsFirstSection) + separatorLineThickness * CGFloat(nrOfItemsFirstSection - 1)
        firstSettingsSectionView?.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0).isActive = true
        firstSettingsSectionView?.heightAnchor.constraint(equalToConstant: totalHeightFirstSection).isActive = true
        firstSettingsSectionView?.widthAnchor.constraint(equalToConstant: contentView.bounds.width - 16.0).isActive = true
    }
class MenuSwitchElementStackView: UIStackView {

    weak var switchMutatedDelegate: SwitchMutatedDelegate?

    let imgViewWidth: CGFloat = 23.0

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    convenience init(frame: CGRect, text: String, icon: UIImage?, onState: Bool, switchID: Int) {
        self.init(frame: frame)
        composeStackView(text: text, icon: icon, onState: onState, switchID: switchID)
    }

    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    fileprivate func composeStackView(text: String, icon: UIImage?, onState: Bool, switchID: Int) {

        // StackView properties
        axis = .horizontal
        alignment = .center
        spacing = 23.0

        var iconImgView: UIImageView?

        // create Icon
        if let icon = icon {
            iconImgView = UIImageView()
            iconImgView?.image = icon
            iconImgView?.contentMode = .scaleAspectFit
        }

        // create Title
        let titleLabel = UILabel()
        titleLabel.font = AppConstants.Font.ListSectionElementTitleFont
        titleLabel.text = text
        titleLabel.textColor = .white
        titleLabel.tintColor = .white
        titleLabel.heightAnchor.constraint(equalToConstant: 19.0).isActive = true

        // create choice TextLbl
        let mySwitch = UISwitch()
        mySwitch.tag = switchID
        mySwitch.setOn(onState, animated: false)
        mySwitch.addTarget(self, action: #selector(MenuSwitchElementStackView.switchChanged(_:)), for: UIControl.Event.valueChanged)

        // text stackView creation
        if let iconImgView = iconImgView {
            addArrangedSubview(iconImgView)
        }
        addArrangedSubview(titleLabel)
        addArrangedSubview(mySwitch)
        // set Constraints
        setConstraints(iconImgView, titleLabel, mySwitch)
    }

    @objc func switchChanged(_ mySwitch: UISwitch) {
        switchMutatedDelegate?.switchChanged(isOn: mySwitch.isOn, switchID: mySwitch.tag)
    }

    fileprivate func setConstraints(_ iconImgView: UIImageView?, _ titleLabel: UILabel, _ mySwitch: UISwitch) {

        translatesAutoresizingMaskIntoConstraints = false
        iconImgView?.translatesAutoresizingMaskIntoConstraints = false
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        mySwitch.translatesAutoresizingMaskIntoConstraints = false

        iconImgView?.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.0).isActive = true
        iconImgView?.widthAnchor.constraint(equalToConstant: 24.0).isActive = true
        iconImgView?.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true

        titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true

        mySwitch.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
        mySwitch.leadingAnchor.constraint(equalTo: trailingAnchor, constant: -64.0).isActive = true
    }
}
class MenuSwitchListSectionView: UIView {

    var sectionElementsStackView: MenuSwitchListSectionWithElementsStackView?
    weak var switchMutatedDelegate: SwitchMutatedDelegate?

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    convenience init(frame: CGRect,
             elementHeight: CGFloat,
    separatorLineThickness: CGFloat,
           backgroundColor: UIColor,
                    titles: [String],
                     icons: [UIImage?]?,
                  onStates: [Bool]) {
        self.init(frame: frame)
        composeView(elementHeight: elementHeight, separatorLineThickness: separatorLineThickness, backgroundColor: backgroundColor, titles: titles, icons: icons, onStates: onStates)
    }

    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func assignDelegate() {
        self.sectionElementsStackView?.switchMutatedDelegate = switchMutatedDelegate
        sectionElementsStackView?.assignDelegate()
    }

    fileprivate func composeView(elementHeight: CGFloat, separatorLineThickness: CGFloat, backgroundColor: UIColor, titles: [String], icons: [UIImage?]?, onStates: [Bool]) {

        // create background View
        let totalHeight: CGFloat = elementHeight * CGFloat(titles.count) + separatorLineThickness * CGFloat(titles.count - 1)
        let backGroundView = ListSectionBackgroundView(frame: .zero, height: totalHeight, backgroundColor: backgroundColor)

        // create stackView
        sectionElementsStackView = MenuSwitchListSectionWithElementsStackView(frame: CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: totalHeight), elementHeight: elementHeight, separatorLineThickness: separatorLineThickness, titles: titles, icons: icons, onStates: onStates)

        // add background and stackView to self
        addSubview(backGroundView)
        addSubview(sectionElementsStackView!)

        // set Constraints
        translatesAutoresizingMaskIntoConstraints = false
        backGroundView.translatesAutoresizingMaskIntoConstraints = false
        sectionElementsStackView?.translatesAutoresizingMaskIntoConstraints = false

        backGroundView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
        backGroundView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        backGroundView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        backGroundView.heightAnchor.constraint(equalToConstant: totalHeight).isActive = true
        sectionElementsStackView?.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
        sectionElementsStackView?.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16.0).isActive = true
        sectionElementsStackView?.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10.0).isActive = true
    }
}
class MenuSwitchListSectionWithElementsStackView: UIStackView {

    weak var switchMutatedDelegate: SwitchMutatedDelegate?
    var elementStackView: MenuSwitchElementStackView?
    var elements: [MenuSwitchElementStackView]?
    var titles: [String]? // needed for gesture callback

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    convenience init(frame: CGRect,
             elementHeight: CGFloat,
    separatorLineThickness: CGFloat,
                    titles: [String],
                     icons: [UIImage?]?,
                  onStates: [Bool]) {
        self.init(frame: frame)
        self.titles = titles // needed for gesture callback
        composeStackView(elementHeight: elementHeight, separatorLineThickness: separatorLineThickness, titles: titles, icons: icons, onStates: onStates)
    }

    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func assignDelegate() {
        if let elements = elements {
            for element in elements {
                element.switchMutatedDelegate = switchMutatedDelegate
            }
        }
    }

    fileprivate func composeStackView(elementHeight: CGFloat, separatorLineThickness: CGFloat, titles: [String], icons: [UIImage?]?, onStates: [Bool]) {

        // stackView properties
        axis = .vertical
        alignment = .leading
        spacing = 0.0

        // create stackView elements
        elements = (0..<titles.count).map { (idx) -> MenuSwitchElementStackView in
            if icons?.count ?? 0 > 0 {
                elementStackView = MenuSwitchElementStackView(frame: .zero, text: titles[idx], icon: icons?[idx], onState: onStates[idx], switchID: idx)
            } else {
                elementStackView = MenuSwitchElementStackView(frame: .zero, text: titles[idx], icon: nil, onState: onStates[idx], switchID: idx)
            }
            elementStackView?.isUserInteractionEnabled = true
            elementStackView?.tag = idx
            return elementStackView!
        }

        var singleLines = [UIView]()
        let lineThickness: CGFloat = separatorLineThickness

        // compose the stackView
        if let elements = elements {
            for (idx, view) in elements.enumerated() {

                // add element to stackView
                addArrangedSubview(view)

                if idx < titles.count - 1 {
                    // add single Line to stackView
                    let singleLineView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: lineThickness))
                    singleLineView.backgroundColor = ImageConverter.UIColorFromRGB(0x606060, alpha: 1.0)
                    singleLines.append(singleLineView)

                    addArrangedSubview(singleLineView)
                }
            }
        }

        // set constraints
        translatesAutoresizingMaskIntoConstraints = false

        if let elements = elements {
            for (idx, element) in elements.enumerated() {
                element.translatesAutoresizingMaskIntoConstraints = false
                element.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
                element.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
                element.heightAnchor.constraint(equalToConstant: elementHeight).isActive = true
                if idx < titles.count - 1 {
                    singleLines[idx].translatesAutoresizingMaskIntoConstraints = false
                    singleLines[idx].topAnchor.constraint(equalTo: element.bottomAnchor).isActive = true
                    singleLines[idx].heightAnchor.constraint(equalToConstant: lineThickness).isActive = true
                    if icons?.count ?? 0 > 0 {
                        if let _ = icons?[idx] {
                            singleLines[idx].leadingAnchor.constraint(equalTo: leadingAnchor, constant: 39.0).isActive = true
                        }
                    } else {
                        singleLines[idx].leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
                    }
                    singleLines[idx].trailingAnchor.constraint(equalTo: trailingAnchor, constant: 9.0).isActive = true
                }
            }
        }
    }
}
class ListSectionBackgroundView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    convenience init(frame: CGRect, height: CGFloat = 60.0, backgroundColor: UIColor) {
        self.init(frame: frame)
        composeView(height: height, backgroundColor: backgroundColor)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    fileprivate func composeView(height: CGFloat, backgroundColor: UIColor) {

        // View properties
        self.backgroundColor = backgroundColor
        self.layer.cornerRadius = 10.0
        self.layer.masksToBounds = true
        self.clipsToBounds = true

        // set Constraints
        setConstraints(height)
    }

    fileprivate func setConstraints(_ height: CGFloat) {
        self.translatesAutoresizingMaskIntoConstraints = false
        self.heightAnchor.constraint(equalToConstant: height).isActive = true
    }
}

推荐答案

我终于找到了解决方案.

I finally found a solution.

是UIView扩展名"anchor"在我的代码中由于某种原因在iOS14下不再起作用.

It was the UIView-extension "anchor" in my code that no longer works under iOS14 for some reason.

在这里,我更精确地描述了问题...

因此,如果我使用扩展名并执行以下操作-那么ViewHierarchy中的所有UIControl均无法正常工作(即不再执行target-actions,switch-didChanges等)

Therefore, if I use the extension and do the following - then any UIControls in my ViewHierarchy do not work (i.e. no target-actions, switch-didChanges, etc will no longer kick-in)

SettingsStackView.anchor(top: safeAreaLayoutGuide.topAnchor, leading: contentView.leadingAnchor, bottom: contentView.bottomAnchor, trailing: contentView.trailingAnchor)

但是,如果我没有UIView扩展名,那么一切都会很好:

However, if I do it without the UIView-extension, then everything works fine:

SettingsStackView.translatesAutoresizingMaskIntoConstraints = false
SettingsStackView.topAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.topAnchor).isActive = true
SettingsStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
SettingsStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
SettingsStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true

也许有人可以告诉我,iOS14为什么会出现这种新行为?

Maybe somebody can tell me why this new behaviour came up with iOS14 ???

这篇关于iOS14:没有UIControl在UIKit Modal ViewController中工作了的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-20 02:55