首页 > 解决方案 > 自定义 UIView 在 UIViewController 中添加为子视图时不响应

问题描述

在那里,我试图将视图代码与我的 UIViewController 分开,显示部分很好,但对用户交互没有任何响应。

例如,我有我的 LoginViewController

class LoginViewController: UIViewController,UITextFieldDelegate {

    let loginView = LoginView(frame: .zero)
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(loginView)
        loginView.centerInSuperview()//extension to center layouts
        loginView.loginButton.addTarget(self, action: #selector(loginPressed(sender:)), for: .touchUpInside)
    }

    @objc func loginPressed(sender:UIButton){
         print("login")
    }
}

登录视图类

class LoginView: UIView {
    fileprivate let containerWidth:CGFloat = 250
    fileprivate let contentWidth:CGFloat = 240
    let containerView:UIView={
        let v = UIView()
        v.backgroundColor = .white
        v.layer.cornerRadius = 8
        return v
    }()
    let passkeyInput:UITextField = {
        let tf = UITextField(frame: .zero)
        tf.placeholder = "PASSKEY"
        tf.textAlignment = .center
        tf.anchor( size: CGSize(width: 240, height: 0))
        tf.isSecureTextEntry = true
        return tf
    }()
    let loginButton:UIButton={
        let button = UIButton()
        button.backgroundColor = .red
        button.setTitle("LOGIN", for: .normal)
        button.anchor( size: CGSize(width: 240, height: 0))
        button.layer.cornerRadius = 8
        return button
    }()
    func setupView() {
        let stackView = UIStackView(arrangedSubviews: [passkeyInput,loginButton])
        stackView.alignment = .center
        stackView.distribution = .equalSpacing
        stackView.axis = .vertical
        stackView.spacing = 20
        stackView.isLayoutMarginsRelativeArrangement = true
        stackView.layoutMargins = UIEdgeInsets(top: 10, left: 5, bottom: 10, right: 5)
        addSubview(containerView)
        containerView.addSubview(stackView)
        containerView.anchor(size: CGSize(width: containerWidth, height: 0))//extension to layout
        stackView.fillSuperview()//extension to layout
        containerView.centerInSuperview()//extension to layout
    }

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

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }
}

我希望在单击登录按钮时看到“登录”,但由于某种原因,这并没有发生。

我尝试了一些不同的东西:

因此,如果我将所有视图代码(LoginView 中的代码)放在 UIViewController 中,我可以毫无问题地看到预期的结果,但这没有抓住重点——尝试将视图和视图控制器分开

如果我更改 ViewController 中的代码,从添加为子视图

view.addSubview(loginView)

替换现有的默认视图,

view = loginView

它适用于这种情况,但我并不总是想要替换视图,有时(大多数时候)需要添加子视图

我试图在这里搜索类似的问题,但没有任何成功,请帮助指出我做错的地方。

提前致谢。

更新: 这是我使用的布局扩展,还没有弄清楚是什么导致了这个问题。

struct AnchoredConstraints {
    var top, leading, bottom, trailing, width, height: NSLayoutConstraint?
    }

extension UIView {

    @discardableResult
    func anchor(top: NSLayoutYAxisAnchor? = nil, leading: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil, trailing: NSLayoutXAxisAnchor? = nil, padding: UIEdgeInsets = .zero, size: CGSize = .zero) -> AnchoredConstraints {

        translatesAutoresizingMaskIntoConstraints = false
        var anchoredConstraints = AnchoredConstraints()

        if let top = top {
            anchoredConstraints.top = topAnchor.constraint(equalTo: top, constant: padding.top)
        }

        if let leading = leading {
            anchoredConstraints.leading = leadingAnchor.constraint(equalTo: leading, constant: padding.left)
        }

        if let bottom = bottom {
            anchoredConstraints.bottom = bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom)
        }

        if let trailing = trailing {
            anchoredConstraints.trailing = trailingAnchor.constraint(equalTo: trailing, constant: -padding.right)
        }

        if size.width != 0 {
            anchoredConstraints.width = widthAnchor.constraint(equalToConstant: size.width)
        }

        if size.height != 0 {
            anchoredConstraints.height = heightAnchor.constraint(equalToConstant: size.height)
        }

        [anchoredConstraints.top, anchoredConstraints.leading, anchoredConstraints.bottom, anchoredConstraints.trailing, anchoredConstraints.width, anchoredConstraints.height].forEach{ $0?.isActive = true }

        return anchoredConstraints
    }

    func fillSuperview(padding: UIEdgeInsets = .zero) {
        translatesAutoresizingMaskIntoConstraints = false
        if let superviewTopAnchor = superview?.topAnchor {
            topAnchor.constraint(equalTo: superviewTopAnchor, constant: padding.top).isActive = true
        }

        if let superviewBottomAnchor = superview?.bottomAnchor {
            bottomAnchor.constraint(equalTo: superviewBottomAnchor, constant: -padding.bottom).isActive = true
        }

        if let superviewLeadingAnchor = superview?.leadingAnchor {
            leadingAnchor.constraint(equalTo: superviewLeadingAnchor, constant: padding.left).isActive = true
        }

        if let superviewTrailingAnchor = superview?.trailingAnchor {
            trailingAnchor.constraint(equalTo: superviewTrailingAnchor, constant: -padding.right).isActive = true
        }
    }

    func centerInSuperview(size: CGSize = .zero) {
        translatesAutoresizingMaskIntoConstraints = false
        if let superviewCenterXAnchor = superview?.centerXAnchor {
            centerXAnchor.constraint(equalTo: superviewCenterXAnchor).isActive = true
        }

        if let superviewCenterYAnchor = superview?.centerYAnchor {
            centerYAnchor.constraint(equalTo: superviewCenterYAnchor).isActive = true
        }

        if size.width != 0 {
            widthAnchor.constraint(equalToConstant: size.width).isActive = true
        }

        if size.height != 0 {
            heightAnchor.constraint(equalToConstant: size.height).isActive = true
        }
    }

}

标签: swift

解决方案


该按钮不会触发触摸事件,因为loginView未设置 ' 框架。您只使用 定义其位置loginView.centerInSuperview()

LoginViewController'sviewDidLoad()方法中添加以下代码,它应该可以工作:

loginView.fillSuperview()

(或其他框架定义)

当您使用 时view = loginView,将frame在其他地方设置,这就是它起作用的原因。


推荐阅读