NSLayoutConstraint rules - ios

I can't see the menu bar (The blue view) when i write this code, but when i change the parameter from 50 to 100 its shows. It seems like it lies behind the status field. I want the constraints to relate to the status bar not the screens top. Someone who knows why?
func setupMenuBar(){
view.addSubview(menuBar)
view.addConstriantswithFormat(format: "H:|[v0]|", views:menuBar)
view.addConstriantswithFormat(format: "V:|[v0(50)]", views:menuBar)
}

You need to constrain your menuBar view to the view's safe area to get it to align with the bottom of the navigation bar.
Tough to do with Visual Format Language though. This alternative method should be easy to understand:
view.addSubview(menuBar)
let guide = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
menuBar.topAnchor.constraint(equalTo: guide.topAnchor, constant: 0.0),
menuBar.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: 0.0),
menuBar.trailingAnchor.constraint(equalTo: guide.trailingAnchor, constant: 0.0),
menuBar.heightAnchor.constraint(equalToConstant: 50.0),
])

If the red view is a navigation bar, you should probably look at not extending edges under top bar; otherwise, you need to constrain the blue view in accordance to the red view.
I prefer using the anchors. It is much easier to read.
For example (Swift):
blueView.topAnchor.constraint(equalTo: redView.bottomAnchor).isActive = true
blueView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
blueView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
blueView.heightAnchor.constraint(equalToConstant: 50).isActive = true

Related

IQKeyboardManager doesn’t work when using safeAreaLayoutGuide

I've got a button whose top anchor is: backButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 2).isActive = true
And I've got a text view whose top anchor is: storyDescription.topAnchor.constraint(equalTo: numOfChapters.bottomAnchor, constant: 16).isActive = true (I've got elements between these but they don't affect this unusual behaviour).
When I tap on the textView it sometimes goes above the view, this only happens when I use view.safeAreaLayoutGuide, But when I don't use view.safeAreaLayoutGuide, it doesn't happen. And again, This only happens when I use view.safeAreaLayoutGuide and all the elements below are connected to the element that uses safeAreaLayoutGuide.

Issue With Overlapping UIViews and Interactivity with UIKit/Swift

I am building an interface in Swift and UIKit targeting iOS. All of my views are programmatically constructed. I am having an issue where a UIView that overlaps another UIView (but does not completely cover it) prevents any tap events from passing through. The layout looks like this:
The navbar at the bottom is a custom view and functions fine. Tapping those buttons changes the active view behind it (the current view is the TextView with the SQL syntax highlighting). Above it is a UILabel (with the text "Connected") and a UIView (the circle with the gradient background). I will refer to this element as the "ButtonView" and the label as the "StatusView". The "StatusView" is anchored to the navbar and the enclosing view, and the "ButtonView" is anchored to the navbar and the "StatusView".
This is the relevant layout code:
view.addSubview(navBar!)
view.addSubview(status)
view.addSubview(button)
status.translatesAutoresizingMaskIntoConstraints = false
status.layer.masksToBounds = true
status.text = "Example String"
status.textColor = .white
status.layer.cornerRadius = 20.0
status.layoutMargins = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0)
button.translatesAutoresizingMaskIntoConstraints = false
button.layer.masksToBounds = true
button.layer.cornerRadius = 35.0
// button.isUserInteractionEnabled = false
// button.backgroundColor = .white
NSLayoutConstraint.activate([
status.bottomAnchor.constraint(equalTo: navBar!.topAnchor, constant: -10.0),
status.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10.0),
status.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -90.0),
status.heightAnchor.constraint(equalToConstant: 50.0),
button.bottomAnchor.constraint(equalTo: navBar!.topAnchor, constant: -10.0),
button.leadingAnchor.constraint(equalTo: status.trailingAnchor, constant: 10.0),
button.widthAnchor.constraint(equalToConstant: 70.0),
button.heightAnchor.constraint(equalToConstant: 70.0)
])
The intended behavior is that even with the "ButtonView" present, the SQL view can still be tapped and edited. However, when the "ButtonView" is present, the SQL view can no longer be focused. If the "ButtonView"'s isUserInteractionEnabled property is set to false or the "ButtonView" is removed, everything behaves correctly. The "StatusView" does not seem to have any adverse effects, without having to edit any of its properties. (Note that there is no gestural behavior currently assigned to the "ButtonView", and that is not a UIButton). The debug view does not seem to show any overlapping layers:
Ideally, I would like to eventually add a gesture recognizer to this view, but wondering if that will forever disallow me from accessing the views that are further in the background? Is it possible to overlap interactive views like this, or am I somehow screwing up the responder chain?

Possible to have fine-grained horizontal Auto Layout control in vertical UIStackView?

I'm currently working with a vertical UIStackView in which each view has a UILabel to be displayed on the left and a UIButton to be displayed on the right. The leading constraint for the label should be different than the trailing constraint for the button and the entire view should take up the width of the screen. The alignment for the stackview is fill and the distribution is fillEqually.
The problem I'm running into is that Auto Layout doesn't seem to be respecting the trailing constraint that I'm trying to set for the button on fill alignment (or any other alignment, for that matter). No matter what I put for it, the system sets it to 20. I've tried center, leading, and trailing alignments but they don't work for what I'm trying to do. Is it possible to have the degree of horizontal layout control I'd like with a vertical stackview?
My constraints (radioButton trailing constraint constant is set to 0):
private func sharedInitialization() {
translatesAutoresizingMaskIntoConstraints = false
textLabel.translatesAutoresizingMaskIntoConstraints = false
radioButton.translatesAutoresizingMaskIntoConstraints = false
addSubview(textLabel)
addSubview(radioButton)
NSLayoutConstraint.activate([
radioButton.widthAnchor.constraint(equalToConstant: 30),
radioButton.heightAnchor.constraint(equalToConstant: 30),
radioButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0),
radioButton.centerYAnchor.constraint(equalTo: centerYAnchor),
textLabel.trailingAnchor.constraint(equalTo: radioButton.leadingAnchor, constant: -10),
textLabel.topAnchor.constraint(equalTo: topAnchor, constant: 22),
textLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
bottomAnchor.constraint(equalTo: textLabel.bottomAnchor, constant: 22)])
}
Visual debugger:
I've looked at Prevent vertical UIStackView from stretching a subview? but that doesn't seem quite applicable to my situation. Thanks in advance for any help!

setting textfield constraints to hold effective in screen sizes 4.5 in to 6.5 in

if I set fixed width it either appears too large for small screen (4.5 in) or too small for large screen (6.5 in)
and
is there any special way to ensure the constraints hold good in all
constraints
Like Jatin mentioned in the comments, you can use leading and trailing anchors relative to the view like this,
textField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
textField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
Or, you could set the width as a multiplier to the width of the view.
textField.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.80).isActive = true
Note: Change the constant and multiplier values to suit your needs.

UIScrollView Subviews not expanding to fill width (Autolayout)

I'm using the following code to constrain a view to the left and right anchors of a parent UIScrollView.
Despite the right anchor and the left anchor being set to the ScrollView's left and right anchors, the view does not expand to fill the scrollview.
Note: The gray background in this image is the UIScrollView's background, so I know that's properly constrained to its parent view.
Code:
self.wtfView.translatesAutoresizingMaskIntoConstraints = false
self.wtfView.backgroundColor = UIColor.orange
self.wtfView.topAnchor.constraint(equalTo: self.passwordField.bottomAnchor, constant: 40.0).isActive = true
self.wtfView.leftAnchor.constraint(equalTo: self.containerView.leftAnchor, constant: 40.0).isActive = true
self.wtfView.rightAnchor.constraint(equalTo: self.containerView.rightAnchor, constant: 40.0).isActive = true
self.wtfView.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
self.wtfView.bottomAnchor.constraint(equalTo: self.containerView.bottomAnchor, constant: 40.0).isActive = true
https://imgur.com/a/U88iW
Edit:
The following code works correctly, but I would prefer to use the left+right anchor technique to specify the width, and not at a width constraint. Shouldn't that be possible?
self.wtfView.translatesAutoresizingMaskIntoConstraints = false
self.wtfView.backgroundColor = UIColor.orange
self.wtfView.topAnchor.constraint(equalTo: self.passwordField.bottomAnchor, constant: 40.0).isActive = true
self.wtfView.leftAnchor.constraint(equalTo: self.containerView.leftAnchor, constant: 40.0).isActive = true
self.wtfView.widthAnchor.constraint(equalTo: self.containerView.widthAnchor, constant: -80.0).isActive = true //THE DIFFERENT ONE
self.wtfView.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
self.wtfView.bottomAnchor.constraint(equalTo: self.containerView.bottomAnchor, constant: 040.0).isActive = true
The reason for this is that the contentView of the UIScrollView still doesn't know that you want it to take up the width of it's parentView.
You can fix this by adding the following constraint in iOS11:
self.containerView.contentLayoutGuide.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
This says "Hey, I want you to lock the content Width to the width of the superview.
Pre iOS 11 you can simply constrain a subview to both the parent view's left and right anchors AND the content view's left and right anchors.
Like so:
self.wtfView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 40.0).isActive = true
self.wtfView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: 40.0).isActive = true
Much like, Aleksei's recommendation you are now constraining the width to a rigid value ( the width of the parent view ), and the scrollview will use that to decide the width of the scrollview.
may be try to provide:
self.wtfView.widthAnchor.constraint(equalTo: self.containerView.widthAnchor, constant: -40.0).isActive = true

Resources