Why does viewDidLayoutSubviews interfere with animations? - ios

I have a view controller where the views are laid out manually (no xib). This is done in viewDidLayoutSubviews. I want to animate one of the views, but the animation doesn't work (no observable motion of the view) because viewDidLayoutSubviews appears to be called immediately as the animation begins.
Relevant portions of code:
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
logo.frame = CGRectMake(0, 0, 640, 360);
}
- (void)shrink
{
[UIView animateWithDuration:0.5 animations:^{logo.frame = CGRectMake(0, 0, 320, 180);}];
}
The shrink method is called when another timer fires, so it's not called straight away on view controller creation.
If I set up logo.frame elsewhere and remove that line from viewDidLayoutSubviews, then the animation works correctly.
What is the explanation for this behaviour, and what is a recommended way to work around it?

Have you tried to call animation method in viewDidApper ? Instead of use viewDidLayoutSubviews try to use viewDidLoad

Related

UITableViewController changes UITableView's frame when app enters back into foreground and becomes active

I have a UITableViewController, that is embedded in a UITabBarController and also managed by a UINavigationController.
The only place that I have been able to customize the UITableViewController's table view frame is in viewDidAppear:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:YES];
[self customizeTableViewAppearance];
}
Here is the customizeTableViewAppearance method:
- (void)customizeTableViewAppearance
{
self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0);
if([UIScreen mainScreen].bounds.size.height == 568) {
[self.tableView setFrame:CGRectMake(0, 60, 320, 460)];
} else {
[self.tableView setFrame:CGRectMake(0, 60, 320, 370)];
}
}
This works perfectly when first using the app, but if you go to the device's home screen, and then resume using the app again, none of the usual view methods are called and the table view has been moved. So for whatever reason, even though view methods are not called, UITableViewController is changing the custom frame that I have set for it's UITableView.
Sure enough, if I move to a different tab, and then revisit the tab again, the view methods are called and the UITableView's frame is correct again.
How can I make it so that if the user leaves the app, and then resumes the app again later, that my frame will stay set and not be reset by the UITableViewController?
It's not really clear why you are manipulating the frame of your UITableViewController's tableView, but in most cases, you shouldn't.
From what you pasted, it seems like are trying to prevent the tableView or its content from appearing underneath your navbar, and your tabbar.
Instead of changing the tableView's frame, you should try one of the following things:
Try setting self.edgesForExtendedLayout = UIRectEdgeNone when initialising your UITableViewController
or:
Make sure self.automaticallyAdjustsScrollViewInsets = YES when initialising your UITableViewController
or, if for some reason you need to manage your tableView's contentInset manually:
Make sure self.automaticallyAdjustsScrollViewInsets = NO when initialising your UITableViewController. Now implement viewDidLayoutSubviews as follows
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
self.tableView.contentInset = UIEdgeInsetsMake(self.topLayoutGuide.length, 0, self.bottomLayoutGuide.length, 0);
}
Edit:
I just saw you're using a Storyboard. You can either set the edgesForExtendedLayout or automaticallyAdjustsScrollViewInsets from within your storyboard, or set them by implementing the -(void)awakeFromNib; method.
Without knowing why you are doing what you're doing, an easy solution to handle that case would be the following - Add this in your tableView's init method:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(customizeTableViewAppearance) name:UIApplicationDidBecomeActiveNotification object:nil];
That way, any time your application becomes active again your tableView will call that method.
The way to fix this was to override the viewDidLayoutSubviews method and place my customizeTableViewAppearance method inside of it:
- (void)viewDidLayoutSubviews
{
[self customizeTableViewAppearance];
}
The UITableView always has the correct frame now.

UIView Animation Fails

So, I want to do some basic animations of labels and later views.
I have a label, I'm trying to get it to move when a view loads, so I call the following method at the end of viewDidLoad:
- (void)animateView {
NSLog(#"animateView");
[UIView animateWithDuration:20 animations:^{
// set new position of label which it will animate to
self.dcFirstRunDaysLabel.frame = CGRectMake(20,320,280,215);
}];
}
Instead of animating, the label appears in position.
I've tried every tutorial and read through the docs. I get no errors.
Any thoughts?
Cheers.
Try calling your animateView method in viewDidAppear. Because in viewDidLoad your view isn't visible yet.
viewDidLoad:
Called after the controller’s view is loaded into memory.
viewDidAppear:
Notifies the view controller that its view was added to a view hierarchy.

presentViewController resets all UIView animations

Say I have two view controllers, A and B. UIView instance viewObject is subview of A in the nib, with frame 0, 0, 100, 100.
Now I execute the following
[UIView animateWithDuration:0.5 animations:^{[viewObject setFrame:CGFrameMake(100, 100, 100, 100)];}];
It worked all fine. But when I call:
[self presentViewController:B animated:YES completion:NULL];
viewObject appears to jump back to the frame before the animateWithDuration:animations: message during the transition of the view controllers.
Likewise when I dismiss B the viewObject is at its position in the nib.
How do I make viewObject stay in the same place?
try to set
[viewObject setClipsToBounds:YES]
at least before the second animation. If you need it not to clip to bounds(because of shadows and such) you can reset the property to no after the second animation is completed.
It worked for me every time I had this problem.

iOS: Animate subview without calling layoutSubviews

In layoutSubviews i layout my child views into appropriate positions, and for some of them apply some transformation. Now i want to make on this subviews repeatable scale animation to draw attention. But, when i launch animation with [UIView animate....], with changing transform property - fired layoutSubviews method, which conflict with animation (it override transform and animation not played).
Is there any good way (without bool flags) to handle this behavior?
Example:
- (void)layoutSubviews {
[super layoutSubviews];
myChildView.transform = CGAffineTransformMake....;
}
- (void)animate {
CGAffineTransform originalTransform = myChildView.transform;
[UIView animateWithDuration:0.1f
delay:0.0f
options:UIViewAnimationOptionAutoreverse
animations:^{
[UIView setAnimationRepeatCount:4];
//next line of code produce calling layoutSubviews
myChildView.transform = CGAffineTransformMakeScale(1.15f, 1.15f);
} completion:^(BOOL finished){
myChildView.transform = originalTransform;
//after this also called layoutSubviews
}];
}
Recently, I have encountered this issue. I override the method viewDidLayoutSubviews inside the view controller to control the animation.
- (void)viewDidLayoutSubviews {
// This method will be called after subview's layoutSubviews.
if (self.shouldAnimated) {
// Do animation at here.
}
}
However, this is just a dirty solution.
I suggest you would do better to not use layoutSubviews. Instead create and position and transform your subviews either inside the init method or a custom method called from the init.
I meet this problem also. And I add another view(called subView) as a subview, and add the myChildView to subView. This will not trigger the layoutSubviews of superview when I change the transform of myChildView. And why, you can see this UIView/CALayer: Transform triggers layoutSubviews in superview.
Is there any good way (without bool flags) to handle this behavior?
Yes. Rid off "layoutSubviews" method and set transform for children views in another method.
[self.parentView setUpChildrenViews];
...
[self.parentView animate];

Animate MapView around screen

I have this animation block:
[UIView animateWithDuration:10 animations:^{
CGPoint centerLeft;
centerLeft.x = self.leftMapPane.center.x - 100;
centerLeft.y = self.leftMapPane.center.y;
CGRect leftMove = CGRectMake(self.leftMapPane.frame.origin.x - 100, self.leftMapPane.frame.origin.x, self.leftMapPane.frame.size.width, self.leftMapPane.frame.size.height);
[self.leftMapPane setFrame:leftMove];
[self.leftMapPane setCenter:centerLeft];
}];
but for some reason although it gets inside the animation block, it doesn't move the mapViews I have around on the screen.
It should be noted that I'm not talking about moving the map but the view that contains the map, aka the mapview.
Any thoughts?
The animation doesn't work in viewDidLoad because at that point the views have been loaded into memory but have not been necessarily added to the view hierarchy. So when you try to animate the views it won't work.
Instead, put your animation call in viewDidAppear and it should work. This way you're sure the views you're animating are in the view hierarchy. I tried this in a sample project using your animation code and it worked fine.

Resources