I have two UILabels next to each other in the view where I will show comments to a post, one for the username and one for the timestamp. I convert the timestamp to an easy format like "1h" for one hour ago, "22m" for 22 minutes ago etc.
These are my two labels:
var usernameLabel: UILabel = {
let usernameLabel = UILabel()
usernameLabel.numberOfLines = 1
usernameLabel.lineBreakMode = .byTruncatingTail
usernameLabel.font = UIFont.boldSystemFont(ofSize: 15)
usernameLabel.textColor = UIColor.darkGray
usernameLabel.translatesAutoresizingMaskIntoConstraints = false
usernameLabel.text = "Username"
usernameLabel.isUserInteractionEnabled = true
usernameLabel.isExclusiveTouch = false
usernameLabel.backgroundColor = .green
return usernameLabel
}()
var commentDateLabel: UILabel = {
let commentDateLabel = UILabel()
commentDateLabel.font = UIFont.systemFont(ofSize: 12)
commentDateLabel.textColor = UIColor.lightGray
commentDateLabel.translatesAutoresizingMaskIntoConstraints = false
commentDateLabel.backgroundColor = .red
return commentDateLabel
}()
I add constraints to both of them to make sure they fit inside my view, like this:
commentDateLabel.leftAnchor.constraint(equalTo: usernameLabel.rightAnchor, constant: 8).isActive = true
commentDateLabel.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -16).isActive = true
usernameLabel.leftAnchor.constraint(equalTo: profilePictureImageView.rightAnchor, constant: 16).isActive = true
The problem I'm facing is, the date is aligned on the far right and the username takes up the entire width. I would like it different - where the label of the username is just as wide as needed and the date taking up the entire space that's left.
In other words: I want the green label to shorten to just fit the text and the red label to take up the entire width that's left, so both of them are next to each other but when a username is too long it will truncate and still show the entire date label. How would I go about this?
You need to set
contentHuggingPriority
to usernameLabel to be higher than the other , also set
contentCompressionResistance
to commentDateLabel to be higher
Related
How can I do to have a title, followed by a few lines of text, followed by a title again and again few lines of text constrained in the middle of a view controller programmatically?
My goal is to have bolded for the titles, and it would be nice to have the textview lines incremented also.
My idea was to create 2 labels, and 2 textviews. And adding those to a textview in this order: label1, t1, label2, t2.
But it doesn't seem to work. I try to avoid defining the same textviews and labels many times. textviews add up if I copy its definition twice but not for labels (maybe it is view related?)
I tried with UIbuttons and it worked.
This is what I tried so far:
import UIKit
class HowToSetupProIGVC: UIViewController {
deinit {print("deinit")}
let textView: UITextView = {
let textView = UITextView()
textView.backgroundColor = .blue //bkgdColor
textView.textAlignment = .left
//textView.frame = CGRect(x: 5, y: 5, width: 5, height: 5)
textView.tintColor = .black
textView.translatesAutoresizingMaskIntoConstraints = false //enable autolayout
textView.heightAnchor.constraint(equalToConstant: 100).isActive = true
textView.widthAnchor.constraint(equalToConstant: 300).isActive = true
return textView
}()
let label: UILabel = {
let l = UILabel(frame:CGRect.zero)
//l.frame = CGRect(x: 5, y: 5, width: 5, height: 5)
l.backgroundColor = .green //bkgdColor
l.font = UIFont.preferredFont(forTextStyle: .headline)
l.translatesAutoresizingMaskIntoConstraints = false //enable autolayout
l.heightAnchor.constraint(equalToConstant: 22).isActive = true
l.widthAnchor.constraint(equalToConstant: 300).isActive = true
return l
}()
override func viewDidLoad() {
super.viewDidLoad()
self.modalUI(arrowButton: false)
self.view.backgroundColor = bkgdColor
customStackHTSProIG ()
}
}
extension HowToSetupProIGVC {
func customStackHTSProIG () {
let label1 = label
let label2 = label
let t1 = textView
let t2 = textView
label1.text = "Title1:"
label2.text = "title2:"
t1.text = """
1. On your profile tap menu
2. Tap settings
3. Tap accounts
4. Tap set up professional account
"""
t2.text = """
1. On your profile tap "Edit profile"
2. Link your created page to your account
"""
//StackView
let stackHTS = UIStackView()
stackHTS.axis = NSLayoutConstraint.Axis.vertical
stackHTS.distribution = .fillEqually
stackHTS.alignment = .center
stackHTS.spacing = 5
stackHTS.backgroundColor = .red
//Add StackView + elements
stackHTS.addArrangedSubview(label1)
stackHTS.addArrangedSubview(t1)
stackHTS.addArrangedSubview(label2)
stackHTS.addArrangedSubview(t2)
self.view.addSubview(stackHTS)
//Constraints StackView
stackHTS.translatesAutoresizingMaskIntoConstraints = false
stackHTS.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
stackHTS.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
//stackHTS.heightAnchor.constraint(equalToConstant: 88).isActive = true
}
}
UILabel & UITextView are both UIKit classes written in Objective-C. They are reference types, NOT value types.
When you write following -
let label1 = label
let label2 = label
let t1 = textView
let t2 = textView
Both label1 & label2 are pointing to the one & same instance of UILabel. So is the case for t1 & t2 as well.
When you add them like this -
//Add StackView + elements
stackHTS.addArrangedSubview(label1)
stackHTS.addArrangedSubview(t1)
stackHTS.addArrangedSubview(label2)
stackHTS.addArrangedSubview(t2)
You expect 2 labels and 2 textViews to be added to the StackView. You are adding only 1 label and 1 textView though.
You expect to see all of following -
label1.text = "Title1:"
label2.text = "title2:"
t1.text = """
1. On your profile tap menu
2. Tap settings
3. Tap accounts
4. Tap set up professional account
"""
t2.text = """
1. On your profile tap "Edit profile"
2. Link your created page to your account
"""
However you are only seeing following -
label2.text = "title2:"
t2.text = """
1. On your profile tap "Edit profile"
2. Link your created page to your account
"""
Solutions -
Create two separate instances of UITextView & UILabel like you have already done for the first two and Add these new instances to stack view as well.
Use one UILabel and remove everything else. Use NSAttributedString API to stylize your text as you want for different sections / paragraphs and assign it to UILabel.attributedText.
I have found lots of similar questions about not receiving touch events and I understand that in some cases, writing a custom hitTest function may be required - but I also read that the responder chain will traverse views and viewControllers that are in the hierarchy - and I don't understand why a custom hitTest would be required for my implementation.
I'm looking for an explanation and/or a link to a document that explains how to test the responder chain. This problem is occurring in Xcode 10.2.1.
My scenario (I am not using Storyboard):
I have a mainViewController, that provides a full screen view with an ImageView and a few Labels. I have attached TapGestureRecognizers to the ImageView and one of the labels - and they both work properly.
When I tap the label, I add a child viewController and it's view as a subview to the mainViewController. The view is constrained to cover only the right-half of the screen.
The child viewController contains a vertical stack view that contains 3 arrangedSubviews.
Each arrangedSubview contains a Label and a horizontal StackView.
The horizontal stackView's each contain a View with a Label as a subview.
The Label in the subview sets it's isUserInteractionEnabled flag to True and adds a TapGestureRecognizer.
These are the only objects in the child ViewController that have 'isUserInteractionEnabled' set.
The Label's are nested fairly deep, but since this is otherwise a direct parent/child hierarchy (as opposed to the 2 views belonging to a NavigationController), I would expect the Label's to be in the normal responder chain and function properly. Do the Stack View's change that behavior? Do I need to explicitly set the 'isUserInteractionEnabled' value to False on some of the views? Is there way I can add logging to the ResponderChain so I can see which views it checked and find out where it is being blocked?
After reading this StackOverflow post I tried adding my gesture recognizers in viewDidLayoutSubviews() instead of what's shown below - but they still do not receive tap events.
Thank you in advance to any who can offer advice or help.
Here is the code for the label that is not responding to my tap events and the tap event it should call:
func makeColorItem(colorName:String, bgColor:UIColor, fgColor:UIColor) -> UIView {
let colorNumber:Int = colorLabelDict.count
let colorView:UIView = {
let v = UIView()
v.tag = 700 + colorNumber
v.backgroundColor = .clear
v.contentMode = .center
return v
}()
self.view.addSubview(colorView)
let tapColorGR:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapColor))
let colorChoice: UILabel = {
let l = UILabel()
l.tag = 700 + colorNumber
l.isUserInteractionEnabled = true
l.addGestureRecognizer(tapColorGR)
l.text = colorName
l.textAlignment = .center
l.textColor = fgColor
l.backgroundColor = bgColor
l.font = UIFont.systemFont(ofSize: 24, weight: .bold)
l.layer.borderColor = fgColor.cgColor
l.layer.borderWidth = 1
l.layer.cornerRadius = 20
l.layer.masksToBounds = true
l.adjustsFontSizeToFitWidth = true
l.translatesAutoresizingMaskIntoConstraints = false
l.widthAnchor.constraint(equalToConstant: 100)
return l
}()
colorView.addSubview(colorChoice)
colorChoice.centerXAnchor.constraint(equalTo: colorView.centerXAnchor).isActive = true
colorChoice.centerYAnchor.constraint(equalTo: colorView.centerYAnchor).isActive = true
colorChoice.heightAnchor.constraint(equalToConstant: 50).isActive = true
colorChoice.widthAnchor.constraint(equalToConstant: 100).isActive = true
colorLabelDict[colorNumber] = colorChoice
return colorView
}
#objc func tapColor(sender:UITapGestureRecognizer) {
print("A Color was tapped...with tag:\(sender.view?.tag ?? -1)")
if let cn = sender.view?.tag {
colorNumber = cn
let v = colorLabelDict[cn]
if let l = (v?.subviews.first as? UILabel) {
print("The \(l.text) label was tapped.")
}
}
}
It looks like the main reason you're not getting a tap recognized is because you are adding a UILabel as a subview of a UIView, but you're not giving that UIView any constraints. So the view ends up with a width and height of Zero, and the label exists outside the bounds of the view.
Without seeing all of your code, it doesn't look like you need the extra view holding the label.
Take a look at this... it will add a vertical stack view to the main view - centered X and Y - and add "colorChoice" labels to the stack view:
class TestViewController: UIViewController {
let stack: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.spacing = 4
return v
}()
var colorLabelDict: [Int: UIView] = [:]
override func viewDidLoad() {
super.viewDidLoad()
let v1 = makeColorLabel(colorName: "red", bgColor: .red, fgColor: .white)
let v2 = makeColorLabel(colorName: "green", bgColor: .green, fgColor: .black)
let v3 = makeColorLabel(colorName: "blue", bgColor: .blue, fgColor: .white)
[v1, v2, v3].forEach {
stack.addArrangedSubview($0)
}
stack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stack)
NSLayoutConstraint.activate([
stack.centerXAnchor.constraint(equalTo: view.centerXAnchor),
stack.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
func makeColorLabel(colorName:String, bgColor:UIColor, fgColor:UIColor) -> UILabel {
let colorNumber:Int = colorLabelDict.count
// create tap gesture recognizer
let tapColorGR:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapColor))
let colorChoice: UILabel = {
let l = UILabel()
l.tag = 700 + colorNumber
l.addGestureRecognizer(tapColorGR)
l.text = colorName
l.textAlignment = .center
l.textColor = fgColor
l.backgroundColor = bgColor
l.font = UIFont.systemFont(ofSize: 24, weight: .bold)
l.layer.borderColor = fgColor.cgColor
l.layer.borderWidth = 1
l.layer.cornerRadius = 20
l.layer.masksToBounds = true
l.adjustsFontSizeToFitWidth = true
l.translatesAutoresizingMaskIntoConstraints = false
// default .isUserInteractionEnabled for UILabel is false, so enable it
l.isUserInteractionEnabled = true
return l
}()
NSLayoutConstraint.activate([
// label height: 50, width: 100
colorChoice.heightAnchor.constraint(equalToConstant: 50),
colorChoice.widthAnchor.constraint(equalToConstant: 100),
])
// assign reference to this label in colorLabelDict dictionary
colorLabelDict[colorNumber] = colorChoice
// return newly created label
return colorChoice
}
#objc func tapColor(sender:UITapGestureRecognizer) {
print("A Color was tapped...with tag:\(sender.view?.tag ?? -1)")
// unwrap the view that was tapped, make sure it's a UILabel
guard let tappedView = sender.view as? UILabel else {
return
}
let cn = tappedView.tag
let colorNumber = cn
print("The \(tappedView.text ?? "No text") label was tapped.")
}
}
Result of running that:
Those are 3 UILabels, and tapping each will trigger the tapColor() func, printing this to the debug console:
A Color was tapped...with tag:700
The red label was tapped.
A Color was tapped...with tag:701
The green label was tapped.
A Color was tapped...with tag:702
The blue label was tapped.
I have one view whose height is 50
myView.heightAnchor.constraint(equalToConstant: 50).isActive = true
Now what I want to do is when I click button (buton1), I want to change its height to 20. So I make below and it's working fine.
myView.heightAnchor.constraint(equalToConstant: 20).isActive = true
Now in myView I have another button (button2), when I click on it, I want to go back to previous height of 50, but it's not working.
myView.heightAnchor.constraint(equalToConstant: 50).isActive = true
Problem is here. Now the view is not re-sizing like when click on button1.
Note :
When I click on button1 & use below code, re-size also not work.
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true
What I found is if I try to re-size to higher size of current size, it don't work.
Any idea why view is not re-sizing?
Edit 1
Even I wrote below after updating height anchor but still not working.
myView.layoutIfNeeded()
self.view.layoutIfNeeded()
Edit 2
Working Option 1
When click on button1, I do below and works.
myView.heightAnchor.constraint(equalToConstant: 40).isActive = true
When click on button2, I do below and works.
myView.heightAnchor.constraint(equalToConstant: 30).isActive = true
Not Working Option 2
When click on button1, I do below and works.
myView.heightAnchor.constraint(equalToConstant: 40).isActive = true
When click on button2, I do below and NOT WORK.
myView.heightAnchor.constraint(equalToConstant: 50).isActive = true
So what I found is I change height higher then previous, it don't work
At the moment, you are creating a new rule about the view's height every time. iOS doesn't understand how to make a view both 10, 20 and 30 pixels high, so it will do the lowest one. To avoid creating conflicting heights, you need to have one height rule and change that one's constant when needed. Here's a somewhat contained example.
class CoolView: UIViewController {
lazy var myView = UIView()
lazy var myViewHeightAnchor = myView.heightAnchor.constraint(equalToConstant: 10)
override func viewDidLoad() {
super.viewDidLoad()
myView.backgroundColor = .black//livesMatters
myView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myView)
NSLayoutConstraint.activate([
myView.topAnchor.constraint(equalTo: view.topAnchor),
myView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
myView.widthAnchor.constraint(equalToConstant: 10),
myViewHeightAnchor
])
}
#objc func someButtonTapped() {
myViewHeightAnchor.constant = 20
view.layoutIfNeeded()
}
#objc func anotherButtonTapped() {
myViewHeightAnchor.constant = 30
view.layoutIfNeeded()
}
}
You should keep the reference to the constraint and change the constant value and then call layoutIfNeeded method to achieve this. Here's how:
// First
let heightConstraint = myView.heightAnchor.constraint(equalToConstant: 50)
heightConstraint.isActive = true
// Then to change
heightConstraint.constant = 20
myView.layoutIfNeeded()
As requested I'm adding playground sample here (try this out on Xcode-playground):
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
var heightConstraint: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
let sampleView = UIView()
sampleView.backgroundColor = .green
sampleView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(sampleView)
heightConstraint = sampleView.heightAnchor.constraint(equalToConstant: 50)
let button = UIButton(type: .contactAdd)
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(handleAction), for: .touchUpInside)
view.addSubview(button)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor),
sampleView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
sampleView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
heightConstraint!,
sampleView.widthAnchor.constraint(equalToConstant: 200)
])
}
#objc func handleAction() {
heightConstraint?.constant = heightConstraint?.constant == 50 ? 30 : 50
}
}
PlaygroundPage.current.setLiveView(ViewController())
Here you can see how updating the heightConstraint changes the height of the sampleView when the button is clicked. I'm toggling between 50 and 30 points in height here.
So short story,
I was adding below line every time I want to update height which is wrong.
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true
With this, what it do is take the least height and set that. Ex If I set height 3 times as 100, 20, 80, it will take 20 as the height even I run with 80.
To avoid this, we have to add a variable for the height constraint
var heightConstraint : NSLayoutConstraint?
Now while adding constraints to view, add as below.
heightConstraint = mainCVView.heightAnchor.constraint(equalToConstant: 50)
heightConstraint!.isActive = true
Now whenever you want to update height do it as below instead of adding constraint again.
heightConstraint?.constant = 0
heightConstraint?.isActive = true
myView.layoutIfNeeded()
This is most important step and not to add constraint the way I was adding in question
So whenever you want to update just update constant as show above. That's it.
Strange bug(s) I'm encountering..
This code:
// Label 1
let textLabel1 = UILabel()
textLabel1.backgroundColor = UIColor.yellow
textLabel1.text = "Label1"
textLabel1.textAlignment = .center
// Label 2
let textLabel2 = UILabel()
textLabel2.backgroundColor = UIColor.blue
textLabel2.text = "Label2"
textLabel2.textAlignment = .center
// Label 3
let textLabel3 = UILabel()
textLabel3.backgroundColor = UIColor.green
textLabel3.text = "Label3"
textLabel3.textAlignment = .center
let h1StackView = UIStackView()
h1StackView.axis = UILayoutConstraintAxis.horizontal
h1StackView.distribution = .fillEqually
h1StackView.alignment = UIStackViewAlignment.fill
h1StackView.spacing = 0
h1StackView.addArrangedSubview(textLabel3)
h1StackView.addArrangedSubview(textLabel2)
self.view.addSubview(h1StackView)
let h2StackView = UIStackView()
h2StackView.axis = UILayoutConstraintAxis.horizontal
h2StackView.distribution = .fillEqually
h2StackView.alignment = UIStackViewAlignment.fill
h2StackView.spacing = 0
h2StackView.addArrangedSubview(textLabel3)
h2StackView.addArrangedSubview(textLabel1)
self.view.addSubview(h2StackView)
//Stack View
let stackView = UIStackView(frame: CGRect(x: 0, y: pos.VERT_STACK_Y, width: pos.SCREEN_WIDTH, height: pos.VERT_STACK_HEIGHT))
stackView.axis = UILayoutConstraintAxis.vertical
stackView.distribution = .fillEqually
stackView.alignment = UIStackViewAlignment.fill
stackView.spacing = 0
stackView.addArrangedSubview(h1StackView)
stackView.addArrangedSubview(h2StackView)
self.view.addSubview(stackView)
Gives this view:
Buggy Image 1
This is close to correct, but wrong because I'm not expecting that big blue bar, rather, half blue - half green.
It gets a little weirder though for me...
If I change just one character in the code (textLabel2 to textLabel1):
(This):
let h1StackView = UIStackView()
h1StackView.axis = UILayoutConstraintAxis.horizontal
h1StackView.distribution = .fillEqually
h1StackView.alignment = UIStackViewAlignment.fill
h1StackView.spacing = 0
h1StackView.addArrangedSubview(textLabel3)
h1StackView.addArrangedSubview(textLabel2)
self.view.addSubview(h1StackView)
(To this):
let h1StackView = UIStackView()
h1StackView.axis = UILayoutConstraintAxis.horizontal
h1StackView.distribution = .fillEqually
h1StackView.alignment = UIStackViewAlignment.fill
h1StackView.spacing = 0
h1StackView.addArrangedSubview(textLabel3)
h1StackView.addArrangedSubview(textLabel1)
self.view.addSubview(h1StackView)
Then I get this view:
Buggy Image 2
It seems there are two problems and I can't quite fix either.. any ideas? I'm hoping this is a me problem and not a Swift/Xcode one.
(P.S. Sorry not enough rep to embed images)
The main problem resides in the logic of that single instance can only be inside one view at a time , so first when you repeated adding lbl3 to both the horizontal stackViews , it appeared at the last one (stack2) , same when you repeated adding 1,3 , they only show inside horizontal stack 2 , so to repeat you have to create another object , also if you decided to create a main stack to hold the 2 horizontal stacks then comment these 2 lines
self.view.addSubview(h1StackView)
self.view.addSubview(h2StackView)
arrangedSubViews is a subset of all subviews —
From the docs on UIView
A parent view may contain any number of subviews but each subview has only one superview.
This is expanded on in addSubView(_:)
Views can have only one superview. If view already has a superview and that view is not the receiver, this method removes the previous superview before making the receiver its new superview.
So when you add textLabel3 to h2StackView in this line:
h2StackView.addArrangedSubview(textLabel3)
You're implicitly removing it from h1StackView
I am trying to update the height of a UITextView based on the content. I have seen this solution but cannot get it to work with my current code (still learning swift)
I define the UITextView as such:
let eventDetailInfoTextBox : UITextView = {
let textbox = UITextView()
textbox.backgroundColor = UIColor.clear
textbox.layer.borderWidth = 1
textbox.layer.borderColor = ColorPallet.AppTertiaryColor.cgColor
textbox.layer.cornerRadius = 10
textbox.setNeedsDisplay()
let contentSize = textbox.sizeThatFits(textbox.bounds.size)
textbox.isEditable = false
return textbox
}()
The subview is then added in setupViews() along with defining its position in the view using a call to setupEventDetailInfoTextBox()
fileprivate func setupEventDetailInfoTextbox() {
print("Event Detail Info Text Box Height: \(eventDetailInfoTextBox.contentSize.height)")
var frame = eventDetailInfoTextBox.frame
frame.size.height = eventDetailInfoTextBox.contentSize.height
eventDetailInfoTextBox.anchor(eventDetailMapView.bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 8, leftConstant: 10, bottomConstant: 0, rightConstant: 10, widthConstant: 0, heightConstant: frame.size.height)
}
The call to .anchor is based on the Lets Build That App frameworks found via this link and basically wraps up the local functions from Xcode. I know this works and have reused the same function repeatedly throughout my app.
The output from the print statement is -8 and is represented by a height suitable to show 1 line of text (sometimes).
Can anyone see why my text box refuses to get any bigger if I have more than 1 line of text?
I'm using IOS 10, Xcode 8 and writing in swift 3.
Follow these step
Create height constraint outlet of TextView.
Calculate content height of Textview.
Update TextView height constraint constant value.
Call layoutIfNeeded() function.
I hope it will work.
If you want something static, down and dirty, you can streamline the process (not set and reset properties) as long as you place everything in the right order. If you need to handle device rotations or other runtime changes, that would require something slightly less down and dirty, but not by much--I'm not sure which you need so I opted for the simpler.
// instance property so that other constraints can refer to it
let descriptionTextView = UITextView()
// configure text view
descriptionTextView.text = descriptionModel
descriptionTextView.font = // UIFont
descriptionTextView.textColor = // UIColor
descriptionTextView.isEditable = false
descriptionTextView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(descriptionTextView)
// set constraints
descriptionTextView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16).isActive = true
descriptionTextView.topAnchor.constraint(equalTo: divider.bottomAnchor, constant: 32).isActive = true
descriptionTextView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -32).isActive = true
descriptionTextView.sizeToFit()
descriptionTextView.layoutIfNeeded()
descriptionTextView.heightAnchor.constraint(equalToConstant: descriptionTextView.contentSize.height).isActive = true