UIStackView Autolayout constraints - uikit

I am creating a UIStackView with two buttons + & -. In the landscape mode the stackview it looks like this with vertical axis.
And in portrait mode it has horizontal axis like this:
Problem: Each button +/- is 50 points high. In landscape, I set w=50 & h=140 for the stack view whereas for portrait I set w=200 & h=50. I set the spacing property of UIStackView of 20 points in landscape and 100 points in portrait. I use 'Vary for Traits' to define different constraints for the two modes as well as customize properties of UIStackView such as Axis, Spacing using 'Add Variation' in storyboard. But on autorotation I get lot of auto-layout errors that I simply can not fix, such as this one:
(
"<NSLayoutConstraint:0x60000009d240 UIButton:0x7fdcc6d152d0.height == 50 (active)>",
"<NSLayoutConstraint:0x60000009d7e0 UIStackView:0x7fdcc6d15110.height == 50 (active)>",
"<NSLayoutConstraint:0x60000009d830 V:|-(0)-[UIButton:0x7fdcc6d152d0] (active, names: '|':UIStackView:0x7fdcc6d15110 )>",
"<NSLayoutConstraint:0x60000009d8d0 V:[UIButton:0x7fdcca006970]-(0)-| (active, names: '|':UIStackView:0x7fdcc6d15110 )>",
"<NSLayoutConstraint:0x61000009f400 'UISV-spacing' V:[UIButton:0x7fdcc6d152d0]-(>=20)-[UIButton:0x7fdcca006970] (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60000009d240 UIButton:0x7fdcc6d152d0.height == 50 (active)>
What do I do I wonder? Seems like I can not change default constraints that come with UIStackView in storyboard.

Related

Leading/Trailing Space to Superview not working for Table View Cell

My UI in Xcode
Result in the Xcode simulator
Constraints for the left side (navy table view cell):
Trailing Space to: Superview
Width equals: 187.5
Bottom Space to: Superview
Height equals: 319
Leading Space to: PollText1 (the other turquoise table view cell)
Top Space to: Poll Username (username label on top of the table view cells)

Override the Autolayout center values of UIButton in a Subview # viewDidLayoutSubviews

I use Autolayout for a fairly complex Menu and really need it. All Buttons, UIViews etc. of my Menu are in a separate UIView called "menuSubview".
If the user presses a button the whole "menuSubview" shifts to another position to reveal other parts of the menu. Sometimes the buttons in the menuSubview move as well. I always save the "Menu State" (with Userdefaults in the get-set variable "lastMenu") and have a function to set the alphas and centers according to the saved "Menu State".
I tried calling the "openLastMenu" function in viewDidAppear, viewDidLayoutSubview - all the "viewDid" functions of the ViewController. The "menuSubview" center and alphas of the buttons always behave as expected... but the centers of the buttons simply won't - no matter what "viewDid" I call the function in.
(the code is a lot more complex - I boiled it down to debug and state my point)
override func viewDidAppear(animated: Bool) {
if lastMenu != nil {openLastMenu()}
}
func openLastMenu(){
menuSubview.center.x = view.center.x //works
menuSubview.center.y = view.center.y + 200 //works
button1.center.x = view.center.x - 50 //why you no behave???
button2.center.x = view.center.x + 50 //why you no behave???
button3.alpha = 0 //works
button4.alpha = 0 //works
}
For debugging I even made a button Subclass to fetch the "center" values with a "didSet" if they change. Seems like after taking the correct values they change once more to their Autolayout-Position.
...oh and ignoring the constraints with "translatesAutoresizingMaskIntoConstraints" on the buttons always fucks up the whole menu. I'm starting to get crazy here :)
If you position views using autolayout, any changes to the frame, like what you do here with the center property, will be ignored.
What you need to do is identify the constraints that are you need to change to move the views in the desired position. Example:
You want to move button1 50 points to the left of view.center. Assuming view is the superview of menuSubview, you would
1) deactivate the the constraint responsible for button1's horizontal placement. How you do this mainly depends on whether you created the constraints in code or Interface Builder. The latter will require you to create outlets for some of the constraints.
2) create a new constraint between button1's centerX anchor and view's centerX anchor with a constant of -50, like so (iOS 9 code)
button1.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor, constant: -50.0).active = true

Xcode - viewDidLayoutSubviews

i have a view inside a viewController, i wanted to start the smaller view outside the viewController in the left, and animate it to the centre when i press a button. so i made it like this:
override func viewDidLayoutSubviews() {
smallView.center = CGPointMake(smallView.center.x - 400, smallView.center.y)
}
And it works perfectly!, the problem is i have a text view inside that smaller view, and every time i start editing it it jumps outside of the main viewController right where it was, and i have to press the button again to bring it inside.
How to fix this?
PS: i tried positioning it to the centre when i start editing the text view like this:
func textViewDidBeginEditing(textView: UITextView) {
smallView.center = CGPointMake(smallView.center.x + 400, smallView.center.y)
}
But it doesn't work. and the method is connected to the textView properly(delegate)
PS2: i also have imagePickerController inside my viewController.
OK, as you're using Auto Layout.
The first rule of Auto Layout (you will see this in any Auto Layout book) is that you absolutely cannot touch the frame or center of a view directly.
// don't do these
myView.frame = CGRectMake(0, 0, 100, 100);
// ever
myView.center = CGPointMake(50, 50);
You can get the frame and center but you can never set the frame or center.
In order to move stuff around using Auto Layout you need to update the constraints.
For instance if I set up a view called myView and want it to grow and shrink in height I would do something like...
Set the top constraint to the superview at 0.
Set the left constraint to the superview at 0.
Set the right constraint to the superview at 0.
Set the height constraint to 50 (for example) and save it in a property called heightConstraint.
Now to animate the change in height I do this...
self.heightConstraint.constant = 100;
[UIView animateWithDuration:1.0
animations:^ {
[self.view layoutIfNeeded];
}];
This will then animate the height from 50 (where it was when I set it) to 100.
This is the same for ANY animation of views using Auto Layout. If (for instance) I had saved the left constraint I could change that and it would increase and decrease the gap from the left edge of the superview to myView.
There are several really good tutorials about AutoLayout on the Ray Wenderlich site. I'd suggest you take a look at them.
Whatever you do, I'd strongly suggest not just disabling Auto Layout. If you don't know how to use Auto Layout then you will very quickly fall behind with iOS 8 and the new device sizes.

How to disable UIScrollView PanGestureRecognizer when scroll to the edge of bounds

I have an UIImageView in an UIScrollView,the imageView's size is 300 * 500,the scrollview bounds is 300 * 300.I set the contentSize 300*500 for scrollview.When i scroll left or right,that is ok,the UIScrollViewPanGestureRecognizer not work because of the width is equal between contentSize and bounds.
When I scroll up or down,even if scrollview's contentoffsetY is 0 or the max 200,the UIScrollViewPanGestureRecognizer has been recognized.I don't want the UIScrollViewPanGestureRecognizer to be recognized at the edge as the super view of the scrollview should handle it.
Hown can i do that?

what's the range of contentOffset

When using setContentOffset, what's the range of contentOffset?
Normally it seems that there's no constraint, but I also found that when the scrollView is in a viewController which is embed in navigationController and the navigationBar is shown, the contentOffset must be smaller than contentSize.(eh,I actually means contentOffset.x < contentSize.width - scrollView.bounds.size.width and contentOffset.height < contentSize.height - scrollView.bounds.size.height). If the contentOffset.x or contentOffset.y is out of that range, then that value is the max value, i.e contentSize.width - scrollView.bounds.size.width.
But when setting the navigationBar hidden, the contentOffset has no constraint, I can set any value and the offset works as wanted.
So did I miss something? why the hidden of navigationBar has effects on scrollView's contentOffset?
I also create a project to illustrate this problem on github.

Resources