可设计的视图未在情节提要中的正确位置呈现
Designable view not rendered at correct position in Storyboard
我有一个自定义的可设计视图 class,如下所示:
@IBDesignable
class AuthInputView: UIView {
static let nibName = "AuthInputView"
@IBOutlet weak var mainContainerView: UIView!
@IBOutlet weak var mainStackView: UIStackView!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var errorLabel: UILabel!
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
fromNib()
}
override init(frame: CGRect) {
super.init(frame: frame)
fromNib()
}
override func awakeFromNib() {
super.awakeFromNib()
}
}
和相应的名为 AuthInputView 的 nib,其文件所有者设置为 AuthInputView。
我有一个在故事板中设计的视图控制器,它有一个视图,class 设置为 AuthInputView。当我 运行 一个应用程序时,它呈现得很好,但是当我在故事板中查看它时,它看起来像这样:
Designables 也是最新的:
但是可以看出,自定义视图呈现在错误的位置(左上角)。
我用来从 nib 加载并在将 nib 的内容添加到指定视图后附加所需约束的代码如下所示:
extension UIView {
@discardableResult
func fromNib<T : UIView>() -> T? {
guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else {
return nil
}
self.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.layoutAttachAll(to: self)
return contentView
}
func layoutAttachAll(to childView:UIView)
{
var constraints = [NSLayoutConstraint]()
childView.translatesAutoresizingMaskIntoConstraints = false
constraints.append(NSLayoutConstraint(item: childView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0))
constraints.append(NSLayoutConstraint(item: childView, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0))
constraints.append(NSLayoutConstraint(item: childView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0))
constraints.append(NSLayoutConstraint(item: childView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0))
childView.addConstraints(constraints)
}
}
是什么导致故事板视图中出现这种错位?
虽然很多人喜欢使用“布局助手”功能,但很容易混淆...
您正在调用您的 layoutAttachAll
函数:
contentView.layoutAttachAll(to: self)
但是在那个函数中,你是这样做的:
func layoutAttachAll(to childView:UIView)
{
var constraints = [NSLayoutConstraint]()
constraints.append(NSLayoutConstraint(item: childView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0))
...
但您已将 self
传递为 childView
,因此您将 self
限制为 self
。
如果您将约束代码“内联”:
func fromNib<T : UIView>() -> T? {
guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else {
return nil
}
self.addSubview(contentView)
var constraints = [NSLayoutConstraint]()
contentView.translatesAutoresizingMaskIntoConstraints = false
constraints.append(NSLayoutConstraint(item: contentView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0))
constraints.append(NSLayoutConstraint(item: contentView, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0))
constraints.append(NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0))
constraints.append(NSLayoutConstraint(item: contentView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0))
self.addConstraints(constraints)
return contentView
}
您应该不会再看到“放错地方”的视图。
如果你真的想使用你的 layoutAttachAll
函数,你想调用它:
self.layoutAttachAll(to: contentView)
并更改最后一行:
// adding to wrong view
//childView.addConstraints(constraints)
self.addConstraints(constraints)
也许值得注意的是,您可以将“助手”扩展大大简化为:
extension UIView {
@discardableResult
func fromNib<T : UIView>() -> T? {
guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else {
return nil
}
self.addSubview(contentView)
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
contentView.frame = bounds
return contentView
}
}
我有一个自定义的可设计视图 class,如下所示:
@IBDesignable
class AuthInputView: UIView {
static let nibName = "AuthInputView"
@IBOutlet weak var mainContainerView: UIView!
@IBOutlet weak var mainStackView: UIStackView!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var errorLabel: UILabel!
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
fromNib()
}
override init(frame: CGRect) {
super.init(frame: frame)
fromNib()
}
override func awakeFromNib() {
super.awakeFromNib()
}
}
和相应的名为 AuthInputView 的 nib,其文件所有者设置为 AuthInputView。
我有一个在故事板中设计的视图控制器,它有一个视图,class 设置为 AuthInputView。当我 运行 一个应用程序时,它呈现得很好,但是当我在故事板中查看它时,它看起来像这样:
Designables 也是最新的:
但是可以看出,自定义视图呈现在错误的位置(左上角)。
我用来从 nib 加载并在将 nib 的内容添加到指定视图后附加所需约束的代码如下所示:
extension UIView {
@discardableResult
func fromNib<T : UIView>() -> T? {
guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else {
return nil
}
self.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.layoutAttachAll(to: self)
return contentView
}
func layoutAttachAll(to childView:UIView)
{
var constraints = [NSLayoutConstraint]()
childView.translatesAutoresizingMaskIntoConstraints = false
constraints.append(NSLayoutConstraint(item: childView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0))
constraints.append(NSLayoutConstraint(item: childView, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0))
constraints.append(NSLayoutConstraint(item: childView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0))
constraints.append(NSLayoutConstraint(item: childView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0))
childView.addConstraints(constraints)
}
}
是什么导致故事板视图中出现这种错位?
虽然很多人喜欢使用“布局助手”功能,但很容易混淆...
您正在调用您的 layoutAttachAll
函数:
contentView.layoutAttachAll(to: self)
但是在那个函数中,你是这样做的:
func layoutAttachAll(to childView:UIView)
{
var constraints = [NSLayoutConstraint]()
constraints.append(NSLayoutConstraint(item: childView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0))
...
但您已将 self
传递为 childView
,因此您将 self
限制为 self
。
如果您将约束代码“内联”:
func fromNib<T : UIView>() -> T? {
guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else {
return nil
}
self.addSubview(contentView)
var constraints = [NSLayoutConstraint]()
contentView.translatesAutoresizingMaskIntoConstraints = false
constraints.append(NSLayoutConstraint(item: contentView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0))
constraints.append(NSLayoutConstraint(item: contentView, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0))
constraints.append(NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0))
constraints.append(NSLayoutConstraint(item: contentView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0))
self.addConstraints(constraints)
return contentView
}
您应该不会再看到“放错地方”的视图。
如果你真的想使用你的 layoutAttachAll
函数,你想调用它:
self.layoutAttachAll(to: contentView)
并更改最后一行:
// adding to wrong view
//childView.addConstraints(constraints)
self.addConstraints(constraints)
也许值得注意的是,您可以将“助手”扩展大大简化为:
extension UIView {
@discardableResult
func fromNib<T : UIView>() -> T? {
guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else {
return nil
}
self.addSubview(contentView)
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
contentView.frame = bounds
return contentView
}
}