A.Roe A.Roe - 3 months ago 462
iOS Question

How to add NSConstraints to UITextView in Swift 3

So I have successfully converted almost all my project to Swift 3 besides from one View Controller where I manually add constraints.

I was getting errors for

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)


So I changed it to

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]


All I am trying to do is add a
UITextView
to a
UIView
in a view controller so it takes up the entire height and width and stays vertically and horizontally in the centre. I'm clearly missing something obvious with my updated code and am unsure why my previous code was refusing to run as I worked in Swift 2.2.

Can anyone answer the correct way of adding constraints in Swift 3 ?

UPDATE:

Here's the error from my original code which was converted to Swift 3.0


2016-09-06 22:08:38.751636 APPNAME[570:65129] -[_SwiftValue
nsli_superitem]: unrecognized selector sent to instance 0x17044a0e0
2016-09-06 22:08:38.752963 APPNAME[570:65129] * Terminating app due
to uncaught exception 'NSInvalidArgumentException', reason:
'-[_SwiftValue nsli_superitem]: unrecognized selector sent to instance
0x17044a0e0'
*
First throw call stack: (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: terminating with uncaught
exception of type NSException (lldb)

Answer

Your first code sample has a syntax error in this line:

textView.addConstraints(constraints: [NSLayoutConstraint])     

Presumably it's trying to create an empty array, but there's no point in adding an empty array of constraints, so just delete the line.

Note that your first code sample (with the erroneous line removed) doesn't meet your requirement (“takes up the entire height and width and stays vertically and horizontally in the centre”). You're specifying margins, so the text view won't take up the entire height and width, and the vertical margins are asymmetric, so it won't be centred vertically.

The problem in your second code sample is that you're using the wrong mask. For example, .flexibleLeftMargin tells the system to allow the distance between the left edge of view and the left edge of textView to change, but that is the opposite of what you want.

This should do what you want:

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

If you want margins, set the frame like this:

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

Note that the size of view must already be at least 16 by 78.