Advice needed on moving UIViews with NSLayoutConstraints - ios

From the images below, when the user taps on view1 I have view2 and view3 slide down to the footer, being effectively pulled by setting the view3's constraint constant with the footer to 0(ish). I have my xib set up with the constraints as shown in the first image. The 2 most important of these [for me right now] are the view1View2 constraint and the view3Footer constraint
To achieve the slide down I've ended up setting a low priority for the view1view2 constraint and a higher priority for the view3Footer constrain, then updating the view3Footer constraint constant in an animateWithDuration
My problem is getting view2 and view3 to slide back up which, if I was using the same method, I'd achieve by setting the view1view2 constraint constant to 2.
I believe that the problem with the above slide up is the greater priority of the view3Footer constraint over the view1View2 constraint, Priorities seem only to be read only so I can't change these specifically. I understand that in setting constraints I'm only requesting the view positioning.
... I believe I might be using the wrong method entirely ...
Am I going about this in the right way at all? Do I have to get the constraint objects IBOutlet and rewrite them? If so, am I rewriting the priorities? Should I just be using >= for the constants with equal priorities, which doesn't seem to work. My code for simply animating down is below, which isn't much but apart from gesture recognisers, the set up is mainly in the xib
Any help is very much appreciated.
Thanks, Steve
For the slide-down:
[UIView animateWithDuration:0.9 animations:^{
_view3FooterConstraint.constant=2;
[self.view layoutIfNeeded];
} completion:^(BOOL finished){}];
UPDATE Also tried this setting priorities to be equal - can no longer achieve slide-down
_view3FooterConstraint.constant=2;
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:0.9 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished){}];
For the slide-up:
[UIView animateWithDuration:0.9 animations:^{
_view1View2Constraint.constant=2;
[self.view layoutIfNeeded];
} completion:^(BOOL finished){}];

I think I would do this by just adding and removing the 2 constraints that change (2's top constraint to 1, and 3's bottom constraint to the footer). Make sure all the views have explicit heights, and make IBOutlets to the 2 constraints I mentioned above. You really only need one of those at a time, but you need to add both in IB so you can make outlets to them. In viewDidLoad, I immediately remove the bottom one. This should work in portrait and landscape. The code I used was:
implementation ViewController {
IBOutlet NSLayoutConstraint *conBottom;
IBOutlet NSLayoutConstraint *conTop;
int pos;
}
-(void)viewDidLoad{
[super viewDidLoad];
pos = 0;
[self.view removeConstraint:conBottom];
[self.view layoutSubviews];
}
-(IBAction)togglePosition:(id)sender { //tap recognizer on view one action method
if (pos == 0) {
[self moveDown];
}else{
[self moveUp];
}
}
-(void)moveDown {
[self.view removeConstraint:conTop];
[self.view addConstraint:conBottom];
conBottom.constant=2;
[UIView animateWithDuration:0.9 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
pos = 1;
}];
}
-(void)moveUp {
[self.view removeConstraint:conBottom];
[self.view addConstraint:conTop];
conTop.constant=2;
[UIView animateWithDuration:0.9 animations:^{
[self.view layoutIfNeeded];
}completion:^(BOOL finished) {
pos = 0;
}];
}

Related

Reduce view and subviews animated

I am currently trying to make a UIView containing some UILabel animate to a new size. But doing so I am having some trouble understanding what is really happening with my view. I read some other post about it but I am still unclear about what is really going on.
In my button I added something that just double the size of the right constraint :
[superView layoutIfNeeded];
rightConst.constant *= 2;
[UIView animateWithDuration:3
animations:^{
[superView layoutIfNeeded];
} completion:nil];
superView Being the view I wanna animate and rightConst the constraint to the right.
But doing so, the animation starts but it is actually coming from left. I don't understand this part. My goal would be to animate just the right side of the view to show the resize and maybe the bottom part of the view but the top left should be fixed.
Thanks.
As described in this document, if you call [aView layoutSubviews], layout of the subviews of aView is forced but layout of aView itself is NOT forced.
You need to call layoutSubviews of the superview of the view you want to animate. In this case, the superview of the superview of the two labels.
Solution is here
UIView *theView;
// theView is the superview of the superview of the two labels.
theView = superView.superview;
[theView layoutIfNeeded];
rightConst.constant *= 2;
[UIView animateWithDuration:3
animations:^{
[theView layoutIfNeeded];
} completion:nil];

Animate view out of screen goes wrong ios

I have a view controller that contains two views. What I need is that after the view controller has been pushed, the view on top (_sidepanelview) moves to the left disappearing of the screen.
Here is what I wrote:
-(void)viewDidAppear:(BOOL)animated{
CGRect newsidepanelviewposition = _sidepanelview.frame;
newsidepanelviewposition.origin.x = -_sidepanelview.frame.size.width;
[UIView animateWithDuration:0.5 delay:1.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
_sidepanelview.frame = newsidepanelviewposition;
} completion:^(BOOL finished) {
NSLog(#"Done!");
}];
}
The problem is that when I run the app, after the view controller been pushed, the view _sidepanelview disappears from the screen and appears again to the center of the screen coming from the right side instead of moving to the left from x=0 to x= -_sidepanelview width disappearing from the screen.
What I'm doing wrong?
Note: I did the app with auto layout unchecked and the animation worked fine, but using it with the auto layout turned on it freaks out!
As your note suggests, Auto Layout is the "culprit".
Your views have constraints that are periodically enforced by the AutoLayout engine. When you alter the frame of a view, the frame changes, but not the view's layout constraints. When the next cycle of layoutSubviews occurs, your views position and size (i.e. frame) will be reset to what the constraints dictate.
If you want to include AutoLayout for that view/viewcontroller, use constraint changes to perform the animation.
The golden rule here is, setFrame is the antithesis of AutoLayout.
Sample code
-(void)viewDidAppear:(BOOL)animated {
_sidePanelLeadingSpace.constant = -_sidepanelview.frame.size.width; // 1
[UIView animateWithDuration:0.5 delay:1.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
[self.view layoutIfNeeded]; // 2
} completion:^(BOOL finished) {
NSLog(#"Done!");
}];
}
Have a reference, _sidePanelLeadingSpace (NSLayoutConstraint), to the leading space constraint of _sidepanelview, for e.g., as an IBOutlet.
Alter the constraint's constant and layout the view by calling layoutIfNeeded in an animation block

UIView animateWithDuration UITableView cause UITableViewCell subview animates too

I am trying to animate change UITableView height constraint using
+ transitionWithView:duration:options:animations:completion:. When the options is set, the UITableViewCell contentView's subview UIView also animates. The effect is like below. As you can see the cell underneath the window goes up and the red dot view's bounds animates to the predefined constraint. If I don't set the animation options, it won't be like this. But I need the animation when I change the UITableView height. So how to keep the table view height animation and disable the table view cell contentView's sub view animation? The code is below. The red dot view is a UIView with a red background color. Is there any way to disable UITableViewCell contentView's subview animation?
- (void)changeTableViewHeight {
self.tableViewTopVerticalSpaceConstraint.constant = 0;
[self.tableView setNeedsUpdateConstraints];
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self.topViewHeightConstraint.constant = 50;
[self.topView setNeedsUpdateConstraints];
}];
}
//1. All constraints change must be done
self.hightConstraint.constant = 200;
self.anotherConstraint.constant = 34;
...
...
// 2. Indimate to iOS that this view need update constraints.
// Hey iOS I have modified few constraints. beware of it to layout that changes.
[self.view setNeedsUpdateConstraints];
// 3. I'm done, relayout the view with animation,
If I really changed any constraints to view.
[UIView animateWithDuration:1.5 animations:^{
[self.view layoutIfNeeded];
}];
Hope somebody will save their time
Had a similar problem that I solved with disabling animation for the layer of the view I didn't want animated. In your case ... implement the awakeFromNib method for your UITableViewCell subclass and disable the animations there. In your case something like ...
override func awakeFromNib() {
super.awakeFromNib()
redCircleView.layer.removeAllAnimations()
}
The thing is that UIView.animateWithDuration animates the views' layers and for new table view cells and other views created during or because of this animation, all changes will also be animated.
... EDIT ...
In the meantime I managed to find an even better solution. In the options parameter for the UIView.animateWithDuration use the UIViewAnimationOptionLayoutSubviews (or .LayoutSubviews in Swift) option. This layouts the subviews at animation commit time.
update code
- (void)changeTableViewHeight {
self.tableViewTopVerticalSpaceConstraint.constant = 0;
self.topViewHeightConstraint.constant = 50;
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
[self.topView setNeedsUpdateConstraints];
}];
}

ios setup constraint to animate an icon

I want to perform the following constraint animation on a magnify icon
At the beginning I want my icon to be at the right of my screen and then move it to the left of my textfield :
___________________
|___________________| O-
to
___________________
O- |___________________|
So what I did is setup a constraint A on the icon to the right of my superview at priority 1000
and add another constraint B on the icon to the left of my textfield at priority 750
then when I want to perform my animation I remove the constraint A so I expected the icon to move to the left of my texfield but it didn't move
How to do that?
constraint A:
Constraint B:
Some code of the animation :
[UIView animateWithDuration:0.5 animations:^{
self.view.alpha = 1;
} completion:^(BOOL finished) {
//animating the icon
[self.view removeConstraint:_loupeSuperviewLeftMargin];//remove constraint A
[self.view setNeedsUpdateConstraints];
UIView animateWithDuration:0.5f animations:^{
[self.view invalidateIntrinsicContentSize];
[self.view layoutIfNeeded];
}];
}];
It worked for me if I gave the icon (I used a button for my test) these 2 constraints to the label (the lower priority constraint could have any priority up to 749 -- if I use 750, both views disappeared),
Then in code, I removed the high priority one,
- (IBAction)moveButton:(id)sender {
[self.view removeConstraint:self.rightCon]; // rightCon is the high priority constraint
[UIView animateWithDuration:1 animations:^{
[self.view layoutIfNeeded];
}];
}
Be sure that you call removeConstraint on whatever view is the superview of the two views that have the spacing constraint between them -- it is that superview that owns that constraint.

change the Vertical constraints in Iphone

I have 2 views(X & Y) in my nib file. I am using Auto-Layout for this.
My second view(Y) is bottom space is 0 to view means it is at bottom of the main View.
My first view (x) is bottom space is 0 to View(Y) means X & Y conncted each other.
If I remove the view (Y) from the coding then View (X) should be place as view (y) means View (X) should be down to mani view bottom.
My try is as follow:
[vwOperation2 removeFromSuperview];
NSLog(#"%#",vwOperation2.constraints);
vwOperation2.translatesAutoresizingMaskIntoConstraints = NO;
[vwOperation2 updateConstraints];
vwOperation1.translatesAutoresizingMaskIntoConstraints = NO;
[vwOperation1 updateConstraints];
[self.view setNeedsLayout];
Help me to solve this..
Thanks in advance...
Never call updateConstraints directly.
Use rather setNeedsUpdateConstraints and needsUpdateConstraints.
Regarding the problem.
In UIView's updateConstraints method add constraints you need considering state of the view. For example:
- (void)updateConstraints {
// You can remove all the constraints here are only some of them
// You may have some IBOutlets for constraints
[self removeConstraints:self.constraints];
if (self.shouldHideX) {
// add proper constrains here
// or modify constants
} else {
// add proper constrains here
// or modify constants
}
[super updateConstraints];
}
Then in you code triggering changes you should do something like:
- (void)doSomethingAwesome {
self.shouldHideX = // determine that
[self.view setNeedsUpdateConstraints];
[self.view setNeedsLayout];
// if you want to animate that
[UIView animateWithDuration:0.2
animations:^{
[self needsUpdateConstraints];
[self layoutIfNeeded];
} completion:^(BOOL finished){
// here e.g. remove your subview from superview
}];
}
Probably my answer will be old-fashioned/not optimal, but it works.
set two IBOutlets for constraints (let's say constraintForViewY and constraintForViewX)
init them with
constraintForViewY.constant = 0
and
constraintForViewX.constant = YView.frame.size.height;
when you delete YView:
constraintForViewX.constant = 0;
(probably with animation)

Resources