如何在 Swift 3 中将 NSConstraints 添加到 UITextView

Posted

技术标签:

【中文标题】如何在 Swift 3 中将 NSConstraints 添加到 UITextView【英文标题】:How to add NSConstraints to UITextView in Swift 3 【发布时间】:2016-09-06 20:59:34 【问题描述】:

所以我已经成功地将我的几乎所有项目转换为 Swift 3,除了我手动添加约束的一个视图控制器。

我遇到了错误

    view.addSubview(textView)

    textView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(textView)

    let views = ["textView": textView]
    var constraints = NSLayoutConstraint.constraints(withVisualFormat: "V:|-70-[textView]-8-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views)
    constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|-8-[textView]-8-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views)
    NSLayoutConstraint.activate(constraints)

所以我改成

textView.translatesAutoresizingMaskIntoConstraints = true
view.addSubview(textView)

textView.center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
textView.autoresizingMask = [UIViewAutoresizing.flexibleLeftMargin, UIViewAutoresizing.flexibleRightMargin, UIViewAutoresizing.flexibleTopMargin, UIViewAutoresizing.flexibleBottomMargin]

我要做的就是在视图控制器中将UITextView 添加到UIView,这样它就占据了整个高度和宽度,并垂直和水平地保持在中心。我的更新代码显然遗漏了一些明显的东西,并且不确定为什么我以前的代码拒绝运行,因为我在 Swift 2.2 中工作。

谁能回答在 Swift 3 中添加约束的正确方法?

更新:

这是我转换为 Swift 3.0 的原始代码中的错误

2016-09-06 22:08:38.751636 APPNAME[570:65129] -[_SwiftValue nsli_superitem]:无法识别的选择器发送到实例 0x17044a0e0 2016-09-06 22:08:38.752963 APPNAME[570:65129] * 终止应用程序到期 未捕获的异常“NSInvalidArgumentException”,原因: '-[_SwiftValue nsli_superitem]: 无法识别的选择器发送到实例 0x17044a0e0' * 第一次抛出调用栈:(0x18430c1c0 0x182d4455c 0x184313278 0x184310278 0x18420a59c 0x184d42104 0x184d40948 0x184d3f79c 0x184d3f340 0x100221ec0 0x1002289ac 0x100228be8 0x18a0e5b08 0x18a19f4cc 0x18a19f3a4 0x18a19e6ec 0x18a19e138 0x18a19dcec 0x18a19dc50 0x18a0e2c78 0x1875ab40c 0x1875a00e8 0x18759ffa8 0x18751cc64 0x1875440d0 0x18a0d8348 0x1842b97dc 0x1842b740c 0x1842b789c 0x1841e6048 0x185c67198 0x18a150bd0 0x18a14b908 0x100171a04 0x1831c85b8) libc++abi.dylib: 以未捕获的方式终止 NSException (lldb) 类型的异常

【问题讨论】:

您的自动布局代码究竟遇到了什么错误? @Vladimir 我已将错误添加到问题中 【参考方案1】:

我在以下代码的最后一行出现了这个错误:

    scrollView = UIScrollView()
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    self.view.addSubview(scrollView)

    contentView = UIView()
    contentView.translatesAutoresizingMaskIntoConstraints = false
    scrollView.addSubview(contentView)

    let viewDict = [
        "contentView": contentView,
        "scrollView": scrollView,
    ]

    let vFormat = "V:|[contentView]|"
    let constraints = NSLayoutConstraint.constraints(withVisualFormat: vFormat, options: [], metrics: nil, views: viewDict)

当我在最后一行设置调试器时,它会将viewDict 类型显示为[String: UIView?](请注意此处的可选)。

当我如下更改声明时不会发生错误:

    let viewDict: [String: UIView] = [

【讨论】:

轰隆隆!也为我修好了!他们如何在 Swift 3 中改变选项的行为真是太烦人了。 这个答案也解决了我的问题。我还能够将代码更改为:let viewDict = ["myView": myView!](添加感叹号)以消除该错误。【参考方案2】:

您的第一个代码示例在此行中有语法错误:

textView.addConstraints(constraints: [NSLayoutConstraint])     

想必它正在尝试创建一个空数组,但是添加一个空约束数组没有意义,所以只需删除该行。

请注意,您的第一个代码示例(删除了错误的行)不符合您的要求(“占据了整个高度和宽度,并垂直和水平地保持在中心”)。您正在指定边距,因此文本视图不会占据整个高度和宽度,并且垂直边距是不对称的,因此不会垂直居中。

第二个代码示例中的问题是您使用了错误的掩码。例如,.flexibleLeftMargin 告诉系统允许view 的左边缘和textView 的左边缘之间的距离发生变化,但这与您想要的相反。

这应该做你想做的:

textView.frame = view.bounds
textView.autoresizingMask = [ .flexibleWidth, .flexibleWidth ]

如果你想要边距,像这样设置框架:

var frame = view.bounds.insetBy(dx: 8, dy: 0)
frame.origin.y += 70
frame.size.height -= 78
textView.frame = frame

请注意,view 的大小必须至少为 16 x 78。

【讨论】:

是的,您提到的第一行只是将代码复制到我的问题时出现的错误,它实际上已被注释掉以进行不同的尝试; 是的,你是对的,现在添加了文本视图并占据了整个视图,但现在我意识到为什么我专门添加了约束,因为文本视图的顶部被导航控制器覆盖.如何在顶部添加 70 个点,向左、右和中心添加 8 个点? 我在添加布局约束时遇到了与 OP (-[SwiftValue nsli_superitem]: unrecognized selector) 完全相同的问题。代码使用 ios9.3 SDK 和 Swift 2.2 构建良好,在 iOS10 设备上运行良好。我认为 iOS10 SDK 更可能出现问题,而不是 Swift2.2 到 Swift3.0 的变化。或者您是否能够使 OP 的第一种方法没有错误地工作?我不热衷于使用幻数和 autoresizingMasks,除非我 _absolutely 必须:-)【参考方案3】:

如果您想继续使用 translatesAutoresizingMaskIntoConstraints=false,而不是接受的答案,请注意以下几点:

1) 当我使用视觉格式化方法生成 NSLayoutConstraints 时,我得到了您遇到的错误 - 在 iOS9.3 SDK 中编译文件并在运行 iOS10 的设备上运行良好的代码 - 使用 iOS10 SDK 构建会因您的错误而崩溃

2) 如果您将其更改为手动创建 NSLayoutConstraints,例如与此类似,然后它按预期工作:

    var allConstraints = [NSLayoutConstraint]()
    allConstraints.append(NSLayoutConstraint(item: slideView, attribute: .left, relatedBy: .equal, toItem: slideButton, attribute: .left, multiplier: 1.0, constant: 0.0))
    allConstraints.append(NSLayoutConstraint(item: slideView, attribute: .right, relatedBy: .equal, toItem: slideButton, attribute: .right, multiplier: 1.0, constant: 0.0))
    allConstraints.append(NSLayoutConstraint(item: slideView, attribute: .top, relatedBy: .equal, toItem: slideButton, attribute: .top, multiplier: 1.0, constant: 0.0))
    allConstraints.append(NSLayoutConstraint(item: slideView, attribute: .bottom, relatedBy: .equal, toItem: slideButton, attribute: .bottom, multiplier: 1.0, constant: 0.0))
    NSLayoutConstraint.activate(allConstraints)

我不知道看起来更优雅的视觉格式有什么问题,但它目前似乎很糟糕(或者在 iOS 9.3 和 10 之间,视图布局代码的顺序发生了变化)。

【讨论】:

我认为这与视图字典的创建方式有关,请查看我的答案。

以上是关于如何在 Swift 3 中将 NSConstraints 添加到 UITextView的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 3 中将 NSConstraints 添加到 UITextView

如何在 swift 3 中将 MKPolylines 添加到 MKSnapShotter?

如何在 swift 3 中将滑动手势添加到 AVPlayer

如何在 Swift 3 中将字典表示为 NSValue?

如何在 Swift 3 中将 NSData 转换为数据?

如何在 swift 3.0 中将此类参数发送到服务器调用