Xcode 8.3.3 Auto Layout on Random Positioned UI Buttons - ios

I am currently making an UI that involves multiple UIButtons in random positions. Please see the photos, I basically want the buttons to stay at where they are suppose to be (aka Pikachu's ear, Pikachu's cheek...) But when I change to a smaller device such as the iPhone SE, the buttons aren't at where I want.
I know that Auto Layout is probably the way out, and I tried adding leading, trailing, top and bottom constraints, but they never work out. I also tried setting suggested constraints, did not work. Some buttons were stretched after setting constraints...
So it really caused headache for me. Can anyone please help?
Desired Layout
UPDATE:
I have found a really easy way to achieve such layout. By unclicking default autoresizing and only select the inner constraints, the buttons can now be at where I want them to be.
Storyboard Edit

You need to add as minimum constraints like
1.) Leading
2.) Top
3.) Height, Width
The key is to change the values either programmatically.
For example,
Suppose, the screen is 320 * 480 and the button Position is to be at (100,250),
the ratios we get will be PositionX = 100/320 = 0.3125
& PositionY = 250/480 = 0.520 then programmatically set
leadingConstraint.constant = 0.312 * self.view.bounds.size.width
topConstraint.constant = 0.520 * self.view.bounds.size.height
You need to calculate these values for each button and set them accordingly.

Related

Swift: Programmatically change size of a button in runtime

I use two buttons in a camera app to track the zoom of said camera. My goal is to reduce the height & width of 1x if 2x is selected and vice-versa but it doesn't seem to work.
I tried button.frame.size.height = 8 button.frame.size.width = 8 and the height & width always remain the same. I even tried 500 to see if it would make a difference and it didn't.
I also tried button.size(CGFloat) to no avail...
I should probably mention that those buttons are nested in a StackView and the app is built on Storyboards. Also, the app is designed to be used on iOS 13+.
Thanks in advance!
UIStackView is using Auto Layout for arranging its subviews. Therefore, direct modifications of the button's frame will have no effect because Auto Layout will anyway recalculate all frames according to the active constraints on the next layout pass.
Since you're using a storyboard, here's how to solve it:
Open the storyboard, select your button and create a width and a height constraint for it.
Create IBOutlets for each of these constraints in your view controller. For the sake of the example let's say you name it buttonWidthConstraint and buttonHeightConstraint.
Whenever you want to change the size of the button, do this:
buttonWidthConstraint.constant = 8
buttonHeightConstraint.constant = 8

Button not correctly located with autolayout after updating constraints

I'm stuck with a strange bug with Auto Layout.
I have two buttons (confirm and delete) side by side, in the same view, each taking a width that's 50% of their superview, and in some situations (when test = true), I want to hide confirm button so delete button takes all the width of the screen.
Here is my autolayout:
Confirm button:
Delete button:
Proportional width is 50% (1:2) of the superview. Now here is my call, happening in viewWillAppear:
if test {
self.confirmButtonWidthConstraint.constant = 0
self.deleteButtonWidthConstraint.constant = (self.deleteButton.superview?.frame.width)!
}
However, after doing so here is the result:
And after checking the UI debugger, I can see that oddly, this delete button now has a width of... 480, with a starting x of -160. So I don't really know what's happening here. Please help!
May I suggest a different tactic?
Embed your buttons in a stack view (UIStackView) with the buttons set to fill equally.
You can then set your button to disappear with button.isHidden = true. The stack view will handle the layout for you gracefully.
You've set the width proportionally but are updating the constraints constant property. This will need lead to the result you desire as the proportional width will simply add the constant value to the multiplier result.
Instead you should set the multiplier property of your constraints. For example:
if test {
self.confirmButtonWidthConstraint.multiplier = 0.0
self.deleteButtonWidthConstraint.multiplier = 1.0
}

Autolayout problems in bigger devices

I am developing an iPhone app in which, i have made this page using autolayout
but it shows unwanted spaces above Register Me(yellow button) in bigger iPhones
Constraints given are:
top,bottom, leading and trailing with respect to its subviews to all the controls. (there is no warning or misplaced constraints i see in xcode)
Here is the screenshot of iPhone 4s
Here is the screenshot of iPhone 6+
I want to minimize the empty spacing in bigger iPhones...
How do i solve this problem?
Please help and thanks in advance
Heres a suggestion for you. You have roughly seven regions of interest there. First one is the title 'Register Kano .. ' etc. Then there are 5 text entry areas - name, email, password, etc. Finally you have 3 small lines of info text - I would count this as one final area, so 7 in all.
What I would do is create 7 parent UIViews to put that stuff in. I would give them 'equal height' constraints, and make them sit above and below each other with no gap. Then as the iphone screen changes height, those areas stretch out height-wise to fill the area. Heres a rough mockup :
Select all those UIViews and select the 'equal heights' constraint :
Then every view except the bottom one needs these constraints (top, leading trailing to superview 0px)
Then your bottom view needs those plus 'bottom' too :
So all that remains to do is to put your content in each of those boxes, but centre them in terms of vertical position relative to their superview.
If your intent to target iOS 9 users, you should use UIStackView, the provide a lot of flexibility in terms of alignment and distribution.
If not, then you or your design team has to find a solution.
You can update the margin contraints of your controls on big devices.
This would add space between each rows on big screens, will looks better as you ask.
Something like :
myControl.heightConstraint.constant += 20.0f
This is how I would do, but you have to decide how you update your layout for big devices
#Krunal you can use the size class and set the constraints accordingly so it will give a brief idea how to fit the UI design for every device!!
you can set constraints relative to height of your base view. This will make your interface objects evenly distributed over layout. Lets assume you have 8 regions. for registerLabel
registerLabel.leading = baseView.leading
registerLabel.trailing = baseView.trailing
registerLabel.top = baseView.top
registerLabel.bottom = baseView.bottom * (1/8)// it will be always proportional to height of view
then for icons at the beginning firstIcon
firstIcon.leading = baseView.leading + 10
firstIcon.height = firstIcon.width
firstIcon.height = baseView.height*(1/9)// to give a gap between icons
firstIcon.bottom = baseView.bottom * (2/8)
and then you can set textfield's constraints according to firstIcon
for other icons you can go on with 3/8, 4/8, 5/8, 6/8 and set the relative textfields constraints according to that icon.
and lastly for registerMe button
registerButton.leading = baseView.leading
registerButton.trailing = baseView.trailing
registerButton.bottom = baseView.bottom
registerLabel.height = baseView.height * (1/8)
With this approach your icons size also decrease and increase relatively with height of view and all the page will be filled.
baseView is view of controller.
What is happening here, you kept the width according to superview ie phone width, but your height is fixed.
Do one thing instead of giving Height constraint, use aspect ration in combination with leading , trailing and top constraint. When view will stretch widthwise , your component's height will also Increase and fill the extra space for iphone 6.
This is the best thing you can do keeping the same layout and design pattern.
Seems you have given some fixed height in views.
As every element is depends on it above and below elements constraints, this might be possible of empty space.
So try to divide the View part then the dependency of constraints will reduce.
If you don't want to show empty space, then use center horizontally to one of the element which will look good, here it may be the third field.
Then start giving same constraints to Register button. Sure it will help you in resolving this issue.
Hey its the best solution for you is stackView
Combine your objects in single stackView.
You can combine your object vertically and also horizontally.
It will decrease your space and view will arranged in awesome manner.
You can select your objects like this.
Click here to make it stack.
Now you can reduce your space like this.

Storyboard constraints using ScrollView aren't respected

I'm quite new to iOS, specially to complex views using Storyboards. I've started to develop the following screen trying to use AutoLayout so I don't need to worry about different iDevices screen sizes.
I'm using ScrollView to move the content to visible space while need to input some info with the keyboard. The thing is I re-created all the constraints a lot of times trying to make the fields respect the width of the ScrollView. Actually, when running, all the fields are being displayed larger than the ScrollView width (it's like overflowing the screen width to the right). The curious thing is that the button respects its width. When I change the orientation to landscape on iPhone 6s Plus those fields has smaller width than the screen width as if I had defined a specific size and the button continue to respect the size according to it constraints. Any thoughts?
Hierarchy:
View Controller
View A
Scroll View
View B
Logo / App name / UITextFields / Switch / Button / Link
Basically the Scroll is constrained with View A. View B is constrained by equal width with to View A and to Scroll margins.
Current Xcode version: 7.2 (7C68)
Please find the constraints added to scrollview i.e top,left,right,bottom constraints.
At the same way set constraints for individual elements inside scrollview i.e textfield and button. For these elements , set left,right,top and height constraints. I have added in my code to achieve your functionality see screenshot below.
Scroll view constraint - top,bottom,leading,trailing ,
View B constraint - top,bottom,leading,trailing and must height-width constraint set ,
Other element - leading, centrally vertical and must height-width ratio
please try, this will help to solve your issue.
First I would like to thanks Bharath and Dhaval for their answers, they were really helpful.
Although the answers helped me to have a better behavior in this view, it turned out that my problem weren't related to the ScrollView but with a mask I'm applying to those fields and the moment where those mask were applied.
I was applying these mask to get a customized round corner so I had the corners exactly like the post image:
// Change webservice's text field style
CAShapeLayer *shape = [[CAShapeLayer alloc] initWithLayer:self.url.layer.mask];
UIBezierPath *shadow = [UIBezierPath bezierPathWithRoundedRect:self.url.bounds byRoundingCorners:(UIRectCornerAllCorners) cornerRadii:CGSizeMake(5, 5)];
shape.path = shadow.CGPath;
self.url.layer.mask = shape;
But this mask were applied in viewDidLoad. Changing to viewDidLayoutSubviews solved my problem and I get the right design and behavior in portrait or landscape: round corners where they should be round and respecting the constraints.
Two other sources from stackoverflow I didn't found before and may be useful for people having problem with ScrollView:
https://stackoverflow.com/questions/31015026/autolayout-and-uiscrollview-storyboard-constraints-are-not-respected
UIScrollView Scrollable Content Size Ambiguity

Working with AutoLayout in Portrait and Landscape

Auto Layout, as good as it is, driving me crazy with constraints. I have the portrait mode designed in IB but I can't get the desired landscape orientation to work.
Notice that when the orientation changes to landscape, the spacing between the UIImageView blocks decreases and the text alignment of SAMPLE TEXT changes to right aligned.
Currently, I have added a few constraints for it to work. However, I need to keep the space between UIImageView blocks fixed, as a result of which it looks cramped up in portrait and fine in landscape. I need it to be spread out evenly in portrait and compress in landscape (like in image above). Similarly, currently my constraints bring up the text but it doesnot keep it at the center of screen and right aligned.
Is this possible at all with Auto Layout? If so, how? Help greatly appreciated.
There are several ways to approach this. One way is to enclose your 3 image views in a UIView. Give the top and bottom image views constraints to the top and bottom respectively, and give the middle one a centerY constraint. Give this enclosing view a fixed height and width, and a constraint to the top of the controller's view. Make an IBOutlet to the height constraint for this enclosing view, and change it on rotation. In the example below, I gave it a height of 350 in portrait:
-(void)updateViewConstraints {
[super updateViewConstraints];
if (self.view.bounds.size.height < self.view.bounds.size.width) {
self.heightCon.constant = self.view.bounds.size.height;
}else{
self.heightCon.constant = 350;
}
}
As for the label, the easiest way is to remove the constraints you have (bottom and centerX), and add trailing and centerY on rotation.
Yes, it can be done with Auto Layout. If you want the spacing between views to increase and/or decrease depending on orientation, you can use the Less Than or Equal or Greater Than or Equal relation (instead of Equal) for the constraint, which allows a distance to grow or shrink:
Play around with that and you should be able to get what you want.
Yes, it is definitely possible to do this with Auto Layout. Through a series of steps, that I think might be too long to post as an answer, you can retain the spacing between your ImageViews and keep the alignment of the text the same.
Essentially, you will have to pin a corner of each ImageView and remove some constraints so that it doesn't automatically compress the spacing when you change the orientation.
Full explanation on how to do this (pretty much exactly what you are asking for) is explained in this tuorial. You can find it about halfway through the page.
Hope this is what you were looking for.

Resources