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
}
Related
I have a stack with 2 view inside it, the yellow takes up 70% of the stack and the green the other 30%. I want to code a button that will upon click:
Expand the stack to the top of the screen, which I have done via:
myStack.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
Then make the green box take up the whole stack, so the screen will be completely green
I have done the 70:30 thing with "equal widths constraint like so: widths
How may I achieve this functionality and what is the code of resetting everything back to normal? desired output
Change the stackView distribution to be Fill Proportionally.
Set up width constraints indepedently for each view (with priority = 999, allowed to break). (0.7 of superview.width for first & 0.3 of superview.width for second).
Call firstView.isHidden = true, it will automatically stretch the secondView to cover stackView in full - Expanded state.
Call firstView.isHidden = false, it will bring you back to Initial state.
So I am trying to implement some feature restrictions based on permissions in an app. The feature in question works on a button that is placed at the bottom of the VC in main.storyboard.
There is another button that I want to remain there. They are aligned horizontally, but not in a horizontal stack view. They have an equal-width constraint and together take up the whole vertical space at the bottom.
I want to hide the first one, and thus have the second one take up that entire horizontal space from left to right, but only when the access to the first button is supposed to be restricted. I've tried doing this in viewNeedsRefresh:
let equalWidthConstraint = firstButton.superview?.constraints.filter{
$0.firstItem as? UIButton == firstButton && $0.secondItem as? UIButton == secondButton
}.first
equalWidthConstraint?.isActive = false
firstButton.isHidden = true
secondButton.frame = CGRect(x: 0, y: firstButton.frame.origin.y, width: self.view.frame.width, height: firstButton.frame.height)
But all this does is hide the first button, while the second button is suddenly partially off-screen. If I try without manually disabling the constraint, I get it looking cleaner but the second button is still in its original position, likely because it still maintains the original width due to the constraint.
Personally, in my opinion, I'd do the following:
remove the equal widths constraint
set a width constraint on one of the buttons set to 0.5x the superview width, then create an outlet for the constraint
set the other button with a trailing or leading (depending on the button you chose) to zero.
When you need to collapse the button, you can now set the constraint's constant directly like so:
buttonWidth.constant = 0
That would hide the view and give you the desired effect.
It turns out they built a re-usable component for this in the past before I joined, but did not actually use it more than once. I have converted the page to use that component instead. Sorry guys.
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.
I have in my app one UITextField on the left and one UIButton on the right. The textfield is anchored on the left at the superview (a container view) and in the right to the button.
So in the left of textfield there is a
leading space = 0 in relation of container
and on the right a
trailing space = 0 in relation of button
but if I move the button on the right way, changing the x origin value, why the textfield don't enlarge its width?
(obviously the button has its constraints about width and height and for position, but not that lock the textfield)
so if I do this
self.mybutton.frame = CGRectMake(self.mybutton.frame.origin.x+100, self.mybutton.frame.origin.y, self.mybutton.frame.size.width, self.mybutton.frame.size.height);
the button moved in the right direction but the textfield seems to doesn't enlarge its width,.
Do you know why?
Working with both Auto Layout and programmatic positioning/sizing can create a lot of headaches. Part of this is because you have created constraints in Auto Layout, which are basically "rules" that your app must follow when laying out all of it's views, and when you change the frame, bounds, or center properties you may be invalidating those rules. But since Auto Layout is not constantly recalculating the layout of your views, problems may go unnoticed until a layout recalculation is triggered.
So to answer your question, changing the frame of the button does not change the text because Auto Layout has no idea that anything has changed. Plus you haven't changed the constraints on the button so if you did call - (void) setNeedsUpdateConstraints on your text field and button, the change you are looking for won't happen. The button will move back to it's initial position, the one you set with constraints.
What you may want to do is create an IBOutlet on whatever is controlling how the button gets positioned on the x-axis (i.e. its trailing space...if that is what you are using). Then instead of doing:
self.mybutton.frame = CGRectMake(self.mybutton.frame.origin.x+100, self.mybutton.frame.origin.y, self.mybutton.frame.size.width, self.mybutton.frame.size.height);
You could do something like:
self.mybuttonXconstraint.constant = self.mybuttonXconstraint.constant + 100
[self.parentView setNeedsUpdateConstraints]
The second line is to ensure that Auto Layout knows a constraint has been changed and that it should recalculate the layout for any views involved with the parent's constraints.
This may be of interest to you as well - iOS Developer Library - Auto Layout Guide
Could you try animating the button's trailing constraint?
Like so (I changed the constraint inside an animation block for illustration purposes):
UIView.animateWithDuration(
5.0,
animations: {
self.buttonTrailingMarginConstraint.constant = 0
self.view.layoutIfNeeded() // Necessary when changing constraints.
}
)
Final result:
Git clone project: https://github.com/backslash-f/animating-constraints
I have a UIView buttonView and gave it an equal heights constraint to the super UIView with a 0.4 multiplier. The frame is adjusted correctly but the subviews of buttonView are not visible. However, when I click on the position where the buttons are supposed to be then the actions triggers.
This does not happen when I change the buttonViews constraint to be a fixed height.
I can get more into details if you want but has anyone run into something similar?
EDIT
There should be two buttons where the white space underneath the label is. When I click on the white space the timer runs but the button is not visible.
I took a look at the project and the issue I saw in a couple places was that auto layout and manual frame transformations are both used, which can be tricky. A couple specific things I saw that you will probably need to modify in order for the view to adapt and render correctly at different sizes / orientations:
1) The CustomAudioLearn view loads a view from a xib and adds it as a subview. However, it does not set constraints on this subview to make sure that the subview always hugs the edges of the parent view. So changing the size of the CustomAudioLearn view through auto layout in the storyboard results in the the xib-based subview always staying the same size. You should either add constraints to the subview or override layoutSubviews() in CustomAudioLearn and include self.customView.frame = self.bounds and self.customViw.layoutIfNeeded() in there. Also, I would suggest removing the line self.customView.translatesAutoresizingMaskIntoConstraints = false
2) Similarly, the RecordButtonView sets its corner radius on awakeFromNib(), but after layout happens, that's no longer the right radius. So you should again consider overriding layoutSubviews() or similar location to adjust the radius every time the layout is updated.
3) Lastly, the superview of the RecordButtonView in the storyboard is set to a height constraint of 70 with a priority of 1000. If you want the RecordButtonView to expand for the space available, you should reduce the priority of that height constraint so that the proportional width of the RecrodButtonView and the 1:1 aspect ratio take priority in determining the height of the superview. Otherwise, it will always be 70 points, or there will be conflicting constraints.
The problem was that I set the rounded corners to half of my frame's width. The radius got so big that it completely hide the view. I changed it so that after the bounds are set I change the corner radius. Sorry for confusion but thanks for any help!