在UIViewController中添加为子视图时,自定义UIView不响应



在那里,我正在尝试将视图代码与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")
}
}

LoginView类

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()
}
}

我本以为点击login按钮时会看到"login",但由于某种原因,这并没有发生。

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

因此,如果我将所有视图代码(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
}
}
}

按钮不会触发触摸事件,因为未设置loginView的帧。只能使用loginView.centerInSuperview()定义其位置。

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

loginView.fillSuperview()

(或其他帧定义)

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

最新更新