UIView animateWithDuration UITableView cause UITableViewCell subview animates too - ios

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];
}];
}

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

Animate UICollectionView items on constraint change in custom layout

I'm using a custom UICollectionview Layout that displays the items in a circle. On a swipe up I reset the constraints on my collectionview and animate those constraint changes. I would like my items to animate with the constraint change so it's one smooth experience.
I get them to animate but only after the constraint change (I think), it looks messy and strange, check the screencast out here: http://cl.ly/ZmA0
This is the code in the swipe gesture method:
- (void)foo:(UISwipeGestureRecognizer *)gesture {
[self.view layoutIfNeeded];
[self.collectionView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(self.view.mas_width);
make.height.equalTo(self.collectionView.mas_width);
make.top.equalTo(self.view.mas_top).offset(50);
}];
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
}];
[self.collectionView performBatchUpdates:^{
CircleLayout *layout = (CircleLayout *)self.collectionView.collectionViewLayout;
} completion:nil];
}
Any suggestions?
I'm not sure what MASConstraintMaker is (and the video is not working).
But within the performBatchUpdates block you are getting the collection view layout. What are you doing with it? it unused. Maybe that can point you to the right solution.

Advice needed on moving UIViews with NSLayoutConstraints

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;
}];
}

UIImageView animation not working correctly

I want to make the width of an UIImageView larger through an animation. I have an UIView with and UIImageView made in the story board. What I want to achieve is so that it looks like the view is scaling from left to right, and keeping its original position. I have tried the following code, but what it does is animating the imageview from the top left corner of its parent view and moving and scaling it until it reaches the position and scale it had from the beginning.
[UIView animateWithDuration:4.0f delay:1.0f options:UIViewAnimationCurveEaseOut animations:^{
CGRect currentFrame = self.imageview1.frame;
currentFrame.size.width = 150;
self.imageview1.frame = currentFrame;
}completion:nil];
Any ideas why this behaviour?
A bit late answer, but I solved the problem. It seems that you cannot change the frame of views in code if autolayout is enabled. Instead you need to animate the constraints of the view, which you can set up in the storyboard and then animate like this:
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.bottomViewY.constant = -196;
[self.view layoutIfNeeded];
} completion:nil];
self.bottomViewY is a constraint which is assigned as an IBOulet. You need to call layoutIfNeeded as it will update the constraints.

Resources