I have an Contentview with uielements inside Uiscrollview. Below screenshot of my storyboard:
I want to add the option for the app that if the user clicks the button it will add label on the bottom of the contentview (below red underscored label - dzialTerminOutlet).
I'm adding the new label programmatically using following code:
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.backgroundColor = UIColor.orange
label.textColor = UIColor.black
label.textAlignment = NSTextAlignment.center
label.text = "test label"
contentView.addSubview(label)
label.topAnchor.constraint(equalTo: dzialTerminOutlet.bottomAnchor, constant: 10).isActive = true
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 85.0)
label.widthAnchor.constraint(equalToConstant: 200.0)
label.heightAnchor.constraint(equalToConstant: 10.0)
The scrollview does not resize though. What's the issue here?
1- You need to activate
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: dzialTerminOutlet.bottomAnchor, constant: 10),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 85.0),
label.widthAnchor.constraint(equalToConstant: 200.0),
label.heightAnchor.constraint(equalToConstant: 10.0)
])
2- You need to remove the bottom constraint established in IB between dzialTerminOutlet and contentView to be able to insert the new one and make the scrollView resize accordingly to avoid conflicts between it and
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 85.0)
so hook it as an outlet and deactivate it or search contentView for the bottom constraint and remove it
Did you set scrollView contentSize with new size?
scrollView.contentSize = CGSize(width: self.contentView.frame.size.width, height: self.contentView.frame.size.height)
a very simple way i'm using it a lot is to connect your contentView height constraint with an IBOutlet object and update it's value.
#IBOutlet weak var contentViewHeight : NSLayoutConstraint!
And after adding your label:
contentViewHeight.constant += labelHeight
Don't forget to set the contentView constraint (top, bottom, leading, trailing) = 0 with scroll view
Related
I'm trying to fix an issue with a UItextview which I placed at the bottom of a viewcontroller programmatically and sometimes it can clip through the bottom of the view if I don't set a constraint like so.
https://i.stack.imgur.com/YfyPi.png
Whenever I try to constraint the textview to the bottom of the safe area, the text needlessly expands too much if there's less text.
https://i.stack.imgur.com/8w1v2.png
Here's the relevant code snippets from the textview and the constraints respectively:
private let summaryTextView: UITextView = {
let summaryTextView = UITextView()
summaryTextView.textColor = .label
summaryTextView.backgroundColor = .customWhite
summaryTextView.textAlignment = .center
summaryTextView.font = UIFont.systemFont(ofSize: 24)
summaryTextView.clipsToBounds = true
summaryTextView.layer.cornerRadius = 20
summaryTextView.layer.masksToBounds = true
summaryTextView.isSelectable = false
summaryTextView.isEditable = false
summaryTextView.isScrollEnabled = false
summaryTextView.translatesAutoresizingMaskIntoConstraints = false
return summaryTextView
}()
private func setupConstraints() {
NSLayoutConstraint.activate([
imageContainerView.topAnchor.constraint(equalTo: view.topAnchor, constant: 120),
imageContainerView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
imageContainerView.heightAnchor.constraint(equalToConstant: 280),
imageContainerView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.4),
summaryTextView.topAnchor.constraint(equalTo: imageContainerView.bottomAnchor,constant: 15),
summaryTextView.leadingAnchor.constraint(equalTo: view.leadingAnchor,constant: 10),
summaryTextView.trailingAnchor.constraint(equalTo: view.trailingAnchor,constant: -10),
summaryTextView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
backgroundImage.fillSuperView(to: view)
bookCover.fillSuperView(to: imageContainerView)
}
Any help would be appreciated!
You need to set the height constraint for UITextView(). Because you are giving fixed top anchor and and bottom anchor so it stretches the textview.
I have my ViewController code as below
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let titleLabel = UILabel()
titleLabel.text = "Hello World!"
view.addSubview(titleLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor),
titleLabel.topAnchor.constraint(equalTo: view.topAnchor),
titleLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor),
titleLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
}
I'm expecting my "Hello World!" to be center aligned. Why wasn't it center aligned? (Vertically it is centered, but horizontally it is aligned to left as shown below.)
p/s: If I remove itleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor), then it is aligned right.
Do you want your label to cover the entire view with the text centered? If so, keep your constraints as they are and set .textAlignment = .center.
I've set the background color of the label to cyan so you can see what's happening:
However, I suspect you just want your label centered in the view. In that case, change your constraints to this:
NSLayoutConstraint.activate([
titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
titleLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
Result:
Until and unless we are not changing priority of constraint the default priority is 1000 for all. So no precedence setting automatically.
For your code, add this line and it will work.
titleLabel.textAlignment = .center
In iOS 9 and later, the default value of textAlignment property of UILabel is NSTextAlignment.natural, prior to iOS 9, the default value was NSTextAlignment.left
If you want your label to cover the entire view with the text-centered then your constraints are perfect, just set
titleLabel.textAlignment = .center
This is my UILabel:
let lblTitle: UILabel = {
let lbl=UILabel()
lbl.textColor=UIColor.darkGray
lbl.textAlignment = .center
lbl.font = UIFont.systemFont(ofSize: 36)
lbl.lineBreakMode = .byWordWrapping
lbl.numberOfLines=0
lbl.translatesAutoresizingMaskIntoConstraints=false
return lbl
}()
I have added lineBreakMode and set numberOfLines=0 which supposed to enable the multiline. My view is added programatically:
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.addSubview(lblTitle)
lblTitle.text="Testing testing testing testing"
lblTitle.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive=true
lblTitle.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive=true
scrollView.addSubview(btnGetChoose)
btnGetChoose.heightAnchor.constraint(equalToConstant: 50).isActive=true
btnGetChoose.widthAnchor.constraint(equalToConstant: 150).isActive=true
btnGetChoose.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive=true
btnGetChoose.topAnchor.constraint(equalTo: lblTitle.bottomAnchor, constant: 10).isActive=true
Why my UILabel won't show in multiple line?
Replace equal to with greater than or equal to.
Try this
lblTitle.heightAnchor.constraint(greaterThanOrEqualToConstant: 50).isActive=true
Also note, you should use leading and trailing anchors (or width constraint) to provide content size to its super view (scrollview).
You have to set width or leading & trailing to wrap
lblTitle.widthAnchor.constraint(equalToConstant: self.view.frame.width / 2).isActive=true
Solved this problem by setting label's leading/trailing anchor as suggested by #keithbhunter
lblTitle.text="Testing testing testing testing"
lblTitle.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive=true
lblTitle.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive=true
lblTitle.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 12).isActive=true
lblTitle.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: -12).isActive=true
If the height of scrollview not set. then scrollview will not scrollable.
To make it scrollable. I set height statically in code like this.
scrollView.contentSize = CGSize(width: self.view.frame.size.width, height: 1000)
Is there any way i can set height dynamically??
If you wanted to do with storyboard then first go through this.
If you wanted to do by code as you done it code then first you have to calculate the inner content height programatically the use the below code.
scrollView.contentSize = CGSize(width: self.view.frame.size.width, height: contentHeight)
Still have any query then ask.
One option using AutoLayout is to make UIStackView a subview of the UIScrollView. Set the constraints (leading, trailing, top, bottom and width) of UIStackView to be equal to UIScrollView. Set the height of the subviews (alternatively make them dynamic to resize depending on their own subviews). Then add the subviews to the UIStackView by using addArrangedSubview and it will handle the constraints for you. The UIScrollView's contentSize will adapt to the UIStackView depending on it's subviews.
Don't forget to change the axis property of UIStackView to vertical.
Here is an example using NSLayoutAnchor:
override func loadView() {
let view = UIView()
view.backgroundColor = .white
let redView = UIView()
redView.backgroundColor = .red
redView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
redView.heightAnchor.constraint(equalToConstant: 400.0)
])
let blueView = UIView()
blueView.backgroundColor = .blue
blueView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
blueView.heightAnchor.constraint(equalToConstant: 700.0)
])
let scrollView = UIScrollView()
scrollView.backgroundColor = .black
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
let stackView = UIStackView()
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(redView)
stackView.addArrangedSubview(blueView)
scrollView.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
])
self.view = view
}
If you don't want to use UIStackView, just add every subview directly to UIScrollView and set the constraints how they relate to each other.
I have a stack view with 3 arranged subviews; a button with a checkbox image, a label with some text and another button with an 'i' image. When the view is created the last button isn't shown for some reason, so I go to debug view hierarchy, where I can see the button in the list of views but nowhere in the actual view. When I then press continue to stop debugging the view hierarchy, the button all of a sudden shows up and squeezes the label a bit so it fits.
If I remove the label, both buttons are shown just fine. If I put the views in a UIView instead of a stack view the 'i' button is not shown. If I shorten the text on the label, the 'i' button is shown correctly. EDIT: I also tried switching the label and the 'i' button and then both are shown correctly as well.
Do you know what methods are called when you continue from debugging that could change the views? Do you know another way to solve this issue?
Thanks
EDIT: Stackviews constraints are just superviews constrainst with some inset constants:
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: view.topAnchor, constant: 12),
stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 12),
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 10)
])
The buttons and label are just added as arranged subviews with no added constraints
Select the StackView go to Attributes Inspector check if Alignment = fill & Distribution = fill Now select the label inside the StackView go to Size Inspector find content Hugging priority & content Compression Resistance Priority the Horizontal priority to less than 250 So the label can easily be stretched and pressed back
Update:
I added 2 buttons and a label I just used text and colour in the buttons to simulate what you need.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let label = UILabel()
let checkmarkButton = UIButton()
let infoButton = UIButton()
label.text = "Jeg acceptere vilkår og betinging"
label.setContentHuggingPriority(240.0, for: .horizontal)
label.setContentCompressionResistancePriority(240, for: .horizontal)
label.textAlignment = .center
checkmarkButton.setTitle("Check", for: .normal)
checkmarkButton.backgroundColor = UIColor.blue
infoButton.setTitle("info", for: .normal)
infoButton.backgroundColor = UIColor.gray
view.addSubview(label)
view.addSubview(checkmarkButton)
view.addSubview(infoButton)
let stackView = UIStackView(arrangedSubviews: [checkmarkButton, label, infoButton])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
stackView.alignment = .fill
stackView.distribution = .fill
view.addSubview(stackView)
// You have set the trailing constant to 12 which is going outside of the screen if you want to set the trailingAnchor constant programmatically it should be negative
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: view.topAnchor, constant: 80),
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -12),
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 12)
])
}