How to make a constraint use the view with highest height from an array of views - ios

Let's assume I have 4 views, 3 in a row and 1 in another row. The ones at the first row have dynamic height and we have no idea how tall they are.
I want to achieve the result from this image:
Basically I want to set View 4's top to bottom of highest view in first row. How can I achieve this?

Use greaterThanOrEqualTo:
view4.topAnchor.constraint(greaterThanOrEqualTo: view1.bottomAnchor, constant: 10).isActive = true
view4.topAnchor.constraint(greaterThanOrEqualTo: view2.bottomAnchor, constant: 10).isActive = true
view4.topAnchor.constraint(greaterThanOrEqualTo: view3.bottomAnchor, constant: 10).isActive = true

Put View1, View2 and View3 inside UIStackView (or regular UIView), and then add constraint between bottom of this new view and top of View4

Related

How to make a UITextView fill up the remaining space

I have a UIButton and UITextField side by side as follows.
I want the Add button to only have a width based on the content. And the text view shall take up the rest of the space. I have the following auto layout constraints.
private func setupLayout() {
newDeviceIdTextField.topAnchor.constraint(equalTo: deviceIdLabel.bottomAnchor, constant: 12).isActive = true
newDeviceIdTextField.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 12).isActive = true
newDeviceIdButton.topAnchor.constraint(equalTo: deviceIdLabel.bottomAnchor, constant: 12).isActive = true
newDeviceIdButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -12).isActive = true
newDeviceIdButton.leadingAnchor.constraint(equalTo: newDeviceIdTextField.trailingAnchor, constant: 0).isActive = true
}
In this article there is a section which I believe exactly solves my problem. But I just don't understand how.
What am I missing here?
A button automatically sizes its width to fit its content, and both a text field and a button have an automatic height. So what you want to do is trivial:
Pin the left of the text field where you want it.
Pin the right of the button where you want it.
Pin the tops of both where you want them.
Pin the right of the text field to the left of the button and set that constant to a small number such as 8.
You can do this without writing code, from storyboard. What i do for this kind of UI is,
Pin the left of the text field where you want it.
Pin the right of the button where you want it.
Pin the tops of both where you want them.
Pin the right of the text field to the left of the button
It's look like in image below
Now Select button > Size Inspector > In Content hugging Priority
Change Horizontal to 750(high) and you done :)
Result look like in image below

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!

UIView in UIScrollView respects some constraints but not other

I need to add a containerView inside a UIScrollView, and then add multiple subviews in the containerView. For some reason, the containerView does not respect the top/bottom/left/rightAnchor constraints, but it works with width/height/centerX/centerYAnchor
NOTE: If the superview is a UIView instead of a UIScrollView, it works fine.
The project is 100% code based. Using Swift 4.1 and Xcode 9.4
This does not work
containerView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0).isActive = true
containerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0).isActive = true
containerView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0).isActive = true
containerView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0).isActive = true
This works
containerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
containerView.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true
containerView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: scrollView.centerYAnchor).isActive = true
In both cases the scrollView.constraints array includes 4 constraints total.
The interesting thing is that the printout of them is different. Some of the constraints that don't work (.top and .left) are printed using the Autolayout Visual Format Language. Also, note the (LTR) in the third one:
ScrollView [
<NSLayoutConstraint:V:|-(0)-[UIView] (active, names: '|':UIScrollView:)>,
<NSLayoutConstraint:UIView.bottom == UIScrollView.bottom (active)>,
<NSLayoutConstraint:H:|-(0)-[UIView](LTR) (active, names: '|':UIScrollView:)>,
<NSLayoutConstraint:UIView.right == UIScrollView.right (active)>]
The constraints that work are printed as follows:
ScrollView [
<NSLayoutConstraint:UIView.width == UIScrollView.width (active)>,
<NSLayoutConstraint:UIView.height == UIScrollView.height (active)>,
<NSLayoutConstraint:UIView.centerX == UIScrollView.centerX (active)>,
<NSLayoutConstraint:UIView.centerY == UIScrollView.centerY (active)>]
I researched StackOverflow and found a couple of questions like this, but they didn't really help me explain what the problem is (or the UIScrollView requirements for constraints).
Any ideas?
UIScrollView needs some contents in it to be scrolled. The view you are adding (inside scrollview), does not have size (height and width), so scroll view can't identify size of its content.
Add size for a view (inside scrollview) and it will work.
containerView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0).isActive = true
containerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0).isActive = true
containerView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0).isActive = true
containerView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0).isActive = true
// Size constraints
containerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
containerView.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true
// To check scrolling of container view; try this
containerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor + 50.0).isActive = true
containerView.heightAnchor.constraint(equalTo: scrollView.heightAnchor + 50.0).isActive = true
It's because the UIScrollView requires it's contentSize to be set in some way. By anchoring the UIView's layout to the sides of the UIScrollView, auto layout still doesn't have an explicit idea of what contentSize of the UIScrollView.
Since the UIScrollView is probably anchored to some parent view, the height and width of the UIScrollView is already defined. By giving a UIView these constraints, auto layout can determine the size of the UIView and then use that size to set the contentSize of the UIScrollView.
Go through the following points in order to use scrollview in your application.
1. First add UIScrollview and give it constrain in view(left, right,width,height).[![enter image description here][1]][1]
2. Now each scrollview has content view which should be there , we cannot add our required views directly to UIScrollview.
3. Add view to scrollview(we name it content view) , give it top,bottom, left and right constrain. Apart from these we need to add height and width constrain to the content view.
4. If you want to have vertical scrollview then give width equal to scrollview and a proper height (like height constrain = 600)or greater than scrollview height.
5. If you want to have horizontal scrollview then give height equal to scrollview and width greater than actual width of scrollview.
Have a look at the constrain of content view added below

How can I get the height of a view if I set its anchors

I am currently trying to access the height of a view which I previously set anchors for. So for example, I set the left, right, top, and bottom anchors of searchTable using the following in my ViewController:
searchTable.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
searchTable.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
searchTable.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
searchTable.bottomAnchor.constraint(equalTo: menuBar.topAnchor).isActive = true
searchTable is an object of a class that I created that inherits from UIView and has a UIImageView in it. I constrain the UIImageView by using the following in the init function:
imageView.topAnchor.constraint(equalTo: topContainer.topAnchor, constant: 10).isActive = true
imageView.leftAnchor.constraint(equalTo: topContainer.leftAnchor, constant: 10).isActive = true
imageView.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: topContainerMultiplier * imageProfileMultiplier).isActive = true
imageView.widthAnchor.constraint(equalTo: self.heightAnchor, multiplier: topContainerMultiplier * imageProfileMultiplier).isActive = true
where:
let topContainerMultipler: Double = 1 / 7
let imageProfileMultipler: Double = 1 / 5
Inside the init function of searchTable, I try want to be able to set the corner radius to be half the image size. I tried to use self.frame.height, self.frame.size.height, self.bounds.height and also getting the .constant value of the self.heightAnchor constraint, but all returns 0.
I would think that there is a solution to get around this, but I haven't been able to find it.
You are querying the height of your view's frame after defining your constraints, but before layout has actually resolved those constraints into a frame rectangle. One approach would be to call layoutIfNeeded to force layout to happen immediately, then use view.frame.size.height. The init method is probably not an appropriate place to do this, as opposed to perhaps inside viewDidLoad on the controller. Or you might do this in viewDidLayoutSubviews to recalculate the corner radius every time your view's layout is updated (in which case you won't need layoutIfNeeded).
Don't use a height constraint if you already use top, bottom, leading, and trailing.
Try to visually debug your view by adding a background color, or using the debug view hierarchy button.
To get the height of a view you should use view.frame.size.height
EDIT (OP question edited)
Your problem is that you try to access the object height when it's just initialized but not displayed yet. You should create a function that update your UI and call it after your view is loaded.

How to display two textfields euqal space in single tableview cell with equal width, edges space

I want to display two textfields in single tableview cell along with some separator between of them both. Those, two textfields has equal space to edges and with the separator. I want to create this in programmatically in tableview cell class in Swift language.
I want this to be fit in all dimension devices.
Note : I am not using autolayout.
Any suggestions?
I highly recommend you to use UIStackViews as it sounds like a perfect use case for your question.
Definition of a UIStackView in the Documentation:
A streamlined interface for laying out a collection of views in either
a column or a row.
It would take care of the resizing behaviour of your views and you could also easily control the margins and the spacing between your elements.
You can use UIStackViews with storyboards or programmatically depending on what you are looking for.
You may also want to read this guide in the documentation to learn more about UIStackViews.
How to use:
Say you have two text fields, textFieldA, textFieldB and your separator view named separatorView.
Here is how you could do setup your UIStackViews programmatically inside your UITableViewCell subclass:
// Create and configure your stack view
let stackView = UIStackView()
stackView.axis = UILayoutConstraintAxis.horizontal
stackView.distribution = UIStackViewDistribution.fillProportionally
stackView.alignment = UIStackViewAlignment.fill
stackView.spacing = 20.0
// Add your textfields and your separator view to the stack view
stackView.addArrangedSubview(textFieldA)
stackView.addArrangedSubview(separatorView)
stackView.addArrangedSubview(textFieldB)
stackView.translatesAutoresizingMaskIntoConstraints = false
// Add your stack view:
self.addSubview(stackView)
// Configure the constraints for your stack view
// (Of course you can set up your stack view the way you want and you don't have to absolutely use constraints, but it's just for the example)
stackView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -20).isActive = true
stackView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 20).isActive = true
stackView.topAnchor.constraint(equalTo: self.topAnchor, constant: 20).isActive = true
stackView.heightAnchor.constraint(equalToConstant: 200.0).isActive = true
It will save you a lot of time as you don't need to add constraints everywhere for all your views, but only for the stack view. The stack view will then take care of its arranged subviews.
One thing you may need in your case, is changing the hugging and compression resistance values for your views, to make sure it looks great on any screens.
As you can see you there are a lot of properties that you can set on your stack view, so just feel free to try different values and set it up the way you like!
Use stack view with axis horizontal and distribution is equal to fillProportionally

Resources