Keyboard dismisses on every character typed in text input in Swift - ios

I have one textField.
private var verseTitle: UITextField = {
let tf = UITextField()
tf.placeholder = "TITLE"
tf.font = UIFont(suite16: .tBlackItalic, size: 18)
tf.textColor = .black.withAlphaComponent(0.5)
tf.returnKeyType = .done
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()
In viewDidLoad method, I have assigned self as delegate.
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
verseTitle.delegate = self
}
In viewDidLayout method, I'm using stack view to add textField to the view.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
//Title
let titleStack = UIStackView()
titleStack.axis = .horizontal
titleStack.alignment = .center
titleStack.distribution = .equalSpacing
titleStack.spacing = 8
titleStack.addArrangedSubview(verseTitle)
titleStack.addArrangedSubview(floorView)
titleStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(titleStack)
NSLayoutConstraint.activate([
floorView.heightAnchor.constraint(equalToConstant: 13),
floorView.widthAnchor.constraint(equalToConstant: 13),
titleStack.centerXAnchor.constraint(equalTo: view.centerXAnchor),
titleStack.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
])
}
Now, the problem I'm facing is, that when I start typing in the textField, the keyboard gets dismissed only after I type one letter. I'm not sure why this is happening. I have to tap on the field after entering each letter. For some reason, the focus is taken away from the field after each letter is entered (unless I tap on a suggested autocorrect - the whole string is correctly added to the string at once)

What's going on here is your view, including the UITextField gets re-created after each keystroke because your view construction is in: viewDidLayoutSubviews(), When the bounds change for a view controller's view, the view adjusts the positions of its subviews and then the system calls this method.
To fix it, move the code to ViewDidLoad, so the view is created only once:
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
verseTitle.delegate = self
let titleStack = UIStackView()
titleStack.axis = .horizontal
titleStack.alignment = .center
titleStack.distribution = .equalSpacing
titleStack.spacing = 8
titleStack.addArrangedSubview(verseTitle)
titleStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(titleStack)
NSLayoutConstraint.activate([
titleStack.centerXAnchor.constraint(equalTo: view.centerXAnchor),
titleStack.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
])
}

Related

Swift - Dynamically resize view after label in it resizes dynamically

I have created a custom view which has an image and a label. I added a tap gesture on it, so when user taps on the view, both label and custom view expands to show the details/more text on the label.
I added code to expand the label which works fine, but the UIView/custom view doesn't get expanded. Below is my code to expand the label.
How do I expand the custom view either programmatically or by adding any constraints?
#objc func bannerTapped(_ sender:UITapGestureRecognizer){
self.bannerMessageLabel.numberOfLines = 0
self.bannerMessageLabel.text = "Unicode characters take up multiple GSM characters. When a Unicode symbol appears in a text, it is usually segmented at the 70-character mark, thus making it even harder for the recipient to decipher the message."
self.bannerMessageLabel.sizeToFit()
self.bannerView.setNeedsLayout()
self.bannerView.layoutIfNeeded()
}
Attaching image. I don't have any constraints on them since I am leaving it on Stack view to handle it.
I created a sample ViewController that does what you need. I think what you were missing is the following anchor:
bannerView.bottomAnchor.constraint(lessThanOrEqualTo: view.bottomAnchor).isActive = true
Sample View Controller:
class TestViewController: UIViewController {
// MARK: - UIObjects
private let bannerView: UIView = {
let bannerView = UIView()
bannerView.translatesAutoresizingMaskIntoConstraints = false
bannerView.backgroundColor = .white
return bannerView
}()
private let stackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical // Works for both horizontal and vertical axis
return stackView
}()
private let bannerWarningImage: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "arrow-right")
imageView.backgroundColor = .orange
return imageView
}()
private let bannerMessageLabel: UILabel = {
let label = UILabel()
label.text = "Unicode characters take up multiple GSM characters. When a Unicode symbol appears in a text"
label.numberOfLines = 0
label.backgroundColor = .green
return label
}()
// MARK: - Overrides
override func viewDidLoad() {
super.viewDidLoad()
bannerView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(bannerTapped)))
addUIElements()
addConstrains()
}
// MARK: - UISetup
private func addUIElements() {
view.backgroundColor = .purple
view.addSubview(bannerView)
bannerView.addSubview(stackView)
stackView.addArrangedSubview(bannerWarningImage)
stackView.addArrangedSubview(bannerMessageLabel)
}
private func addConstrains() {
bannerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
bannerView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
bannerView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
bannerView.bottomAnchor.constraint(lessThanOrEqualTo: view.bottomAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: bannerView.topAnchor).isActive = true
// The -10 for you to see that the bannerView height is actually chaning
stackView.bottomAnchor.constraint(equalTo: bannerView.bottomAnchor, constant: -10).isActive = true
stackView.leadingAnchor.constraint(equalTo: bannerView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: bannerView.trailingAnchor).isActive = true
}
// MARK: - Actions
#objc private func bannerTapped() {
self.bannerMessageLabel.text = "Unicode characters take up multiple GSM characters. When a Unicode symbol appears in a text, it is usually segmented at the 70-character mark, thus making it even harder for the recipient to decipher the message."
}
}

Custom TextField does not comply to constraints

I've been having this issue with HoshiTextField for quite some time now, I also opened an issue on git but didn't get an answer...
This is how it should look like and how it looks like if the user is selecting the textField:
The problem occurs when setting the textField to becomeFirstResponder inside viewDidLoad or when popping a ViewController while the textField inside the first VC was selected. Apparently that messes up the frames or constraints of the textField but I have absolutely no idea how to fix this.
As you can see the "Email-Adesse"-text is moving to the upper left and when pushing and poping back to the ViewController it moves even further outside the constraints. When checking the View Hirarchy with the debugger the "Email-Adresse"-Text looks perfectly in place even though it isn't. Setting up the constraints inside viewDidAppear didn't change anything.
I constrain the textFields like every other element:
let emailTextField: HoshiTextField = {
let v = HoshiTextField()
v.borderActiveColor = .white
v.borderInactiveColor = .white
v.textColor = .white
v.font = UIFont(name: "AvenirNext-Regular", size: 17)
v.placeholder = "Email-Adresse"
v.placeholderColor = .white
v.placeholderFontScale = 0.8
v.minimumFontSize = 13
v.borderStyle = .line
v.autocapitalizationType = .none
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
emailTextField.topAnchor.constraint(equalTo: theLabel.bottomAnchor, constant: 20).isActive = true
emailTextField.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 30).isActive = true
emailTextField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true
emailTextField.heightAnchor.constraint(equalToConstant: 60).isActive = true
If anyone can help me out here I would be so grateful! I hope the problem is clear, you can also look at my project to see the problem yourself:
Git repo to my project
Here is full test controller with 2 alternates of possible solution
Demo: Alternate 1 - often appears already expanded
Demo: Alternate 2 - always there is a delay, expanding is visible
class ViewController2: UIViewController {
#IBOutlet weak var theLabel: UILabel!
private weak var emailTextField: HoshiTextField!
override func viewDidLoad() {
super.viewDidLoad()
emailTextField = {
let v = HoshiTextField()
v.borderActiveColor = .white
v.borderInactiveColor = .white
v.textColor = .white
v.font = UIFont(name: "AvenirNext-Regular", size: 17)
v.placeholder = "Email-Adresse"
v.placeholderColor = .white
v.placeholderFontScale = 0.8
v.minimumFontSize = 13
v.borderStyle = .line
v.autocapitalizationType = .none
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
self.view.addSubview(emailTextField)
emailTextField.topAnchor.constraint(equalTo: theLabel.bottomAnchor, constant: 20).isActive = true
emailTextField.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 30).isActive = true
emailTextField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true
emailTextField.heightAnchor.constraint(equalToConstant: 60).isActive = true
// DispatchQueue.main.async {
// self.emailTextField.becomeFirstResponder() // Alternate 1
// }
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
emailTextField.becomeFirstResponder() // Alternate 2
}
}
Sorry I misunderstood your question at first.
I feel like the issue is that at some point as the HoshiTextField is selected and leaves the screen, it becomes deselected, but it does not update it's layout. So then when you come back the animations still stay relatively the same, but from a different angle.
I'm not sure how to solve that problem precisely, but I was able to get the screen to look normal after adding the following to your EmailVC
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
view.endEditing(true)
}
I hope that that's fine. It's not really solving the issue, but it does get the UI of your app looking proper in this scenario.

Embedd StackView in ScrollView that is embedded in a main StackView

Embedd StackView in ScrollView that is embedded in a main StackView
I am having trouble with a rather complicated detail view that I want to do programmatically. My view hierarchy looks something like this:
Since this might be better explained visualising, I have a screenshot here:
My problem is that I don't know how to set the height constraint on descriptionTextView – right now it's set to 400. What I want though is that it takes up all the space available as the middle item of the main stack view. Once one or more comments are added to the contentStackView, the text field should shrink.
I am not sure which constraints for which views I must set to achieve this...
Here's my take on it so far:
import UIKit
class DetailSampleViewController: UIViewController {
lazy var mainStackView: UIStackView = {
let m = UIStackView()
m.axis = .vertical
m.alignment = .fill
m.distribution = .fill
m.spacing = 10
m.translatesAutoresizingMaskIntoConstraints = false
m.addArrangedSubview(titleTextField)
m.addArrangedSubview(contentScrollView)
m.addArrangedSubview(footerStackView)
return m
}()
lazy var titleTextField: UITextField = {
let t = UITextField()
t.borderStyle = .roundedRect
t.placeholder = "Some Fancy Placeholder"
t.text = "Some Fancy Title"
t.translatesAutoresizingMaskIntoConstraints = false
return t
}()
lazy var contentScrollView: UIScrollView = {
let s = UIScrollView()
s.contentMode = .scaleToFill
s.keyboardDismissMode = .onDrag
s.translatesAutoresizingMaskIntoConstraints = false
s.addSubview(contentStackView)
return s
}()
lazy var contentStackView: UIStackView = {
let s = UIStackView()
s.translatesAutoresizingMaskIntoConstraints = false
s.axis = .vertical
s.alignment = .fill
s.distribution = .equalSpacing
s.spacing = 10
s.contentMode = .scaleToFill
s.addArrangedSubview(descriptionTextView)
s.addArrangedSubview(getCommentLabel(with: "Some fancy comment"))
s.addArrangedSubview(getCommentLabel(with: "Another fancy comment"))
s.addArrangedSubview(getCommentLabel(with: "And..."))
s.addArrangedSubview(getCommentLabel(with: "..even..."))
s.addArrangedSubview(getCommentLabel(with: "...more..."))
s.addArrangedSubview(getCommentLabel(with: "...comments..."))
s.addArrangedSubview(getCommentLabel(with: "Some fancy comment"))
s.addArrangedSubview(getCommentLabel(with: "Another fancy comment"))
s.addArrangedSubview(getCommentLabel(with: "And..."))
s.addArrangedSubview(getCommentLabel(with: "..even..."))
s.addArrangedSubview(getCommentLabel(with: "...more..."))
s.addArrangedSubview(getCommentLabel(with: "...comments..."))
return s
}()
lazy var descriptionTextView: UITextView = {
let tv = UITextView()
tv.font = UIFont.systemFont(ofSize: 17.0)
tv.clipsToBounds = true
tv.layer.cornerRadius = 5.0
tv.layer.borderWidth = 0.25
tv.translatesAutoresizingMaskIntoConstraints = false
tv.text = """
Some fancy textfield text,
spanning over multiple
lines
...
"""
return tv
}()
lazy var footerStackView: UIStackView = {
let f = UIStackView()
f.axis = .horizontal
f.alignment = .fill
f.distribution = .fillEqually
let commentLabel = UILabel()
commentLabel.text = "Comments"
let addCommentButton = UIButton(type: UIButton.ButtonType.system)
addCommentButton.setTitle("Add Comment", for: .normal)
f.addArrangedSubview(commentLabel)
f.addArrangedSubview(addCommentButton)
return f
}()
override func loadView() {
view = UIView()
view.backgroundColor = . systemBackground
navigationController?.isToolbarHidden = true
view.addSubview(mainStackView)
NSLayoutConstraint.activate([
mainStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 12),
mainStackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -12),
mainStackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 12),
mainStackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12),
titleTextField.heightAnchor.constraint(equalToConstant: titleTextField.intrinsicContentSize.height),
contentStackView.leadingAnchor.constraint(equalTo: contentScrollView.leadingAnchor),
contentStackView.trailingAnchor.constraint(equalTo: contentScrollView.trailingAnchor),
contentStackView.topAnchor.constraint(equalTo: contentScrollView.topAnchor),
contentStackView.bottomAnchor.constraint(equalTo: contentScrollView.bottomAnchor),
descriptionTextView.heightAnchor.constraint(equalToConstant: 400),
descriptionTextView.leadingAnchor.constraint(equalTo: mainStackView.leadingAnchor),
descriptionTextView.trailingAnchor.constraint(equalTo: mainStackView.trailingAnchor),
])
}
override func viewDidLoad() {
super.viewDidLoad()
title = "Detail View"
}
func getCommentLabel(with text: String) -> UILabel {
let l = UILabel()
l.layer.borderWidth = 0.25
l.translatesAutoresizingMaskIntoConstraints = false
l.text = text
return l
}
}
You're close, but a couple notes:
When using stack views - particularly inside scroll views - you sometimes need to explicitly define which elements can be stretched or not, and which elements can be compressed or not.
To get the scroll view filled before it has enough content, you need to set constraints so the combined content height is equal to the scroll view frame's height, but give that constraint a low priority so auto-layout can "break" it when you have enough vertical content.
A personal preference: I'm generally not a fan of adding subviews inside lazy var declarations. It can become confusing when trying to setup constraints.
I've re-worked your posted code to at least get close to what you're going for. It starts with NO comment labels... tapping the "Add Comment" button will add "numbered comment labels" and every third comment will wrap onto multiple lines.
Not really all that much in the way of changes... and I think I added enough comments to make things clear.
class DetailSampleViewController: UIViewController {
lazy var mainStackView: UIStackView = {
let m = UIStackView()
m.axis = .vertical
m.alignment = .fill
m.distribution = .fill
m.spacing = 10
m.translatesAutoresizingMaskIntoConstraints = false
// don't add subviews here
return m
}()
lazy var titleTextField: UITextField = {
let t = UITextField()
t.borderStyle = .roundedRect
t.placeholder = "Some Fancy Placeholder"
t.text = "Some Fancy Title"
t.translatesAutoresizingMaskIntoConstraints = false
return t
}()
lazy var contentScrollView: UIScrollView = {
let s = UIScrollView()
s.contentMode = .scaleToFill
s.keyboardDismissMode = .onDrag
s.translatesAutoresizingMaskIntoConstraints = false
// don't add subviews here
return s
}()
lazy var contentStackView: UIStackView = {
let s = UIStackView()
s.translatesAutoresizingMaskIntoConstraints = false
s.axis = .vertical
s.alignment = .fill
// distribution needs to be .fill (not .equalSpacing)
s.distribution = .fill
s.spacing = 10
s.contentMode = .scaleToFill
// don't add subviews here
return s
}()
lazy var descriptionTextView: UITextView = {
let tv = UITextView()
tv.font = UIFont.systemFont(ofSize: 17.0)
tv.clipsToBounds = true
tv.layer.cornerRadius = 5.0
tv.layer.borderWidth = 0.25
tv.translatesAutoresizingMaskIntoConstraints = false
tv.text = """
Some fancy textfield text,
spanning over multiple lines.
This textView now has a minimum height of 160-pts.
"""
return tv
}()
lazy var footerStackView: UIStackView = {
let f = UIStackView()
f.axis = .horizontal
f.alignment = .fill
f.distribution = .fillEqually
let commentLabel = UILabel()
commentLabel.text = "Comments"
let addCommentButton = UIButton(type: UIButton.ButtonType.system)
addCommentButton.setTitle("Add Comment", for: .normal)
// add a target so we can add comment labels
addCommentButton.addTarget(self, action: #selector(addCommentLabel(_:)), for: .touchUpInside)
// don't allow button height to be compressed
addCommentButton.setContentCompressionResistancePriority(.required, for: .vertical)
f.addArrangedSubview(commentLabel)
f.addArrangedSubview(addCommentButton)
return f
}()
// just for demo - numbers the added comment labels
var commentIndex: Int = 0
// do all this in viewDidLoad(), not in loadView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = . systemBackground
navigationController?.isToolbarHidden = true
title = "Detail View"
// add the mainStackView
view.addSubview(mainStackView)
// add elements to mainStackView
mainStackView.addArrangedSubview(titleTextField)
mainStackView.addArrangedSubview(contentScrollView)
mainStackView.addArrangedSubview(footerStackView)
// add contentStackView to contentScrollView
contentScrollView.addSubview(contentStackView)
// add descriptionTextView to contentStackView
contentStackView.addArrangedSubview(descriptionTextView)
// tell contentStackView to be the height of contentScrollView frame
let contentStackHeight = contentStackView.heightAnchor.constraint(equalTo: contentScrollView.frameLayoutGuide.heightAnchor)
// but give it a lower priority do it can grow as comment labels are added
contentStackHeight.priority = .defaultLow
NSLayoutConstraint.activate([
// constrain mainStackView top / bottom / leading / trailing to safe area
mainStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 12),
mainStackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -12),
mainStackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 12),
mainStackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12),
// title text field
titleTextField.heightAnchor.constraint(equalToConstant: titleTextField.intrinsicContentSize.height),
// minimum height for descriptionTextView
descriptionTextView.heightAnchor.constraint(greaterThanOrEqualToConstant: 160.0),
// constrain contentStackView top / leading / trailing / bottom to contentScrollView
contentStackView.topAnchor.constraint(equalTo: contentScrollView.topAnchor),
contentStackView.leadingAnchor.constraint(equalTo: contentScrollView.leadingAnchor),
contentStackView.trailingAnchor.constraint(equalTo: contentScrollView.trailingAnchor),
contentStackView.bottomAnchor.constraint(equalTo: contentScrollView.bottomAnchor),
// constrain contentStackView width to contentScrollView frame
contentStackView.widthAnchor.constraint(equalTo: contentScrollView.frameLayoutGuide.widthAnchor),
// activate contentStackHeight constraint
contentStackHeight,
])
// during dev, give some background colors so we can see the frames
contentScrollView.backgroundColor = .cyan
descriptionTextView.backgroundColor = .yellow
}
#objc func addCommentLabel(_ sender: Any?) -> Void {
// commentIndex is just used to number the added comments
commentIndex += 1
// let's make every third label end up with multiple lines, just to
// confirm variable-height labels won't mess things up
var s = "This is label \(commentIndex)"
if commentIndex % 3 == 0 {
s += ", and it has enough text that it should need to wrap onto multiple lines, even in landscape orientation."
}
let v = getCommentLabel(with: s)
// don't let comment labels stretch vertically
v.setContentHuggingPriority(.required, for: .vertical)
// don't let comment labels get compressed vertically
v.setContentCompressionResistancePriority(.required, for: .vertical)
contentStackView.addArrangedSubview(v)
// auto-scroll to bottom to show newly added comment label
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
let r = CGRect(x: 0.0, y: self.contentScrollView.contentSize.height - 1.0, width: 1.0, height: 1.0)
self.contentScrollView.scrollRectToVisible(r, animated: true)
}
}
func getCommentLabel(with text: String) -> UILabel {
let l = UILabel()
l.layer.borderWidth = 0.25
l.translatesAutoresizingMaskIntoConstraints = false
l.text = text
// allow wrapping / multi-line comments
l.numberOfLines = 0
return l
}
}

Set button width to fit dynamic button title

I have my UI structured say Level 1(UP), Level 2(DOWN) with some controls
In level 1, I have a label L1
In level 2, I have a button and label L2
In level 2 my button may be removed in runtime and I wanted my label L2 to be aligned to leading edge as L1
I'm facing two problems here
When I set my button title programmatically, I want to set my button such that its width grows when text increases and reduces its width when there is less text content. This isn't happening. Please see below screens the constraints I've in place
When I removed my button from superview, I wanted my L2 label Leading to be aligned to L1 leading. So I created a constraint from L2.leading = L1.leading and prioirty is 999
In this case, the button gets reduces its size to almost 0 even if i have text in that. Please advice me setting this up
Problem #1:
use .horizontal UIStackview for the button and text. set its distribution to .fill. For the button set contentCompression resistance priority to .required for .horizontal & set contenHugging priority to .required for .horizontal. So the Button will always wrap the text no matter what.
Problem #2:
While placing inside a stackview, you don't have to remove the button from superview. Just hide it using isHidden.
Code Demonstration
class SampleVC: UIViewController {
private var didAddConstraint = false
// Basic Views
private let label: UILabel = {
let view = UILabel()
view.translatesAutoresizingMaskIntoConstraints = false
view.text = "Label"
return view
}()
private let topButton: UIButton = {
let view = UIButton()
view.translatesAutoresizingMaskIntoConstraints = false
view.setTitle("Button", for: .normal)
view.setTitleColor(.gray, for: .highlighted)
view.backgroundColor = .green
view.setContentHuggingPriority(.required, for: .horizontal)
view.setContentCompressionResistancePriority(.required, for: .horizontal)
return view
}()
private let rightLabel: UILabel = {
let view = UILabel()
view.translatesAutoresizingMaskIntoConstraints = false
view.numberOfLines = 0
view.text = "label"
view.backgroundColor = .red
return view
}()
private lazy var stackview: UIStackView = {
let view = UIStackView()
view.translatesAutoresizingMaskIntoConstraints = false
view.axis = .horizontal
view.distribution = .fill
view.addArrangedSubview(topButton)
view.addArrangedSubview(rightLabel)
return view
}()
override func loadView() {
super.loadView()
view.addSubview(label)
view.addSubview(stackview)
view.setNeedsUpdateConstraints()
view.backgroundColor = .white
}
override func updateViewConstraints() {
super.updateViewConstraints()
if didAddConstraint == false {
didAddConstraint = true
// top label
label.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 16.0).isActive = true
label.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
label.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
// stackview
stackview.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 16.0).isActive = true
stackview.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 8.0).isActive = true
stackview.rightAnchor.constraint(equalToSystemSpacingAfter: view.rightAnchor, multiplier: 16.0).isActive = true
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// TEST Code
// topButton.setTitle("TEST TEST TEST", for: .normal)
// topButton.isHidden = true
}
}

Closures outside viewDidLoad

I'd like to create a simple app without Storyboard. I've created a closure outside the viewDidLoad method, which represents a title on the screen. My problem is that the code contains duplicated lines view.addSubview(label) and it positions the label to the wrong place.
Could you please help me solving this issue?
class HomeVC: UIViewController {
let titleLabel: UILabel = {
let view = UIView()
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
label.text = "Hello"
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(titleLabel)
}
}
I think you want to set the label at the center of HomeVC's view, the problem in the above code is that you are making a new view and place the label inside the view and thats not what you want , so
You just make label first like this:
let titleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Hello"
return label
}()
and then in viewDidLoad add this label as subview of view and apply constraints
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(titleLabel)
setupTitleLabel()
}
func setupTitleLabel() {
titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
titleLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
//you also need to give the label height and width constraints to label here...
}

Resources