I am working on an app that was started by others and I believe started when iOS 5 was current. Most of the UI is code generated and does not use auto layout and constraints explicitly. However, there are some (later added) self contained UI elements, defined in a nib(xib) that use auto layout internally, which are contained by higher level views from the app (generated in code and not using auto layout).
One section of code generates a composite image of one of these self contained elements, animates that image out, and then swaps the image for the actual UI element view. A variety of these self contained UI elements (all based on the same base class but with their own nibs (xib)) can be passed into this routine that displays them as explained. Most of them work just fine in iOS 7 and iOS 8, animating out onto the screen.
However, one specific UI element, on iOS8 only, animates out correctly, but after the completion part of the animation is finished, it resets its position such that its center is at 0,0. This one works fine in iOS 7.
I have compared the code and nibs for the elements that work fine with this one element but don't see anything done differently in the creation and internal composition of the offending UI element.
I added a key path observer to the view for the @"center" key path so I could see who was causing this re-centering and it appears to be in auto layout system code -- none of my code is in the backtrace.
#0 0x002ed826 in -[MyFundsManager observeValueForKeyPath:ofObject:change:context:] at /Users/me/Dev/MyApp/iosapp/MyApp/MyFundsManager.m:158 #1 0x24b30372 in NSKeyValueNotifyObserver () #2 0x24b3001e in NSKeyValueDidChange () #3 0x24b1c840 in -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] () #4 0x27463738 in -[UIView(Geometry) _applyISEngineLayoutValues] () #5 0x273898ee in -[UIView(Geometry) _resizeWithOldSuperviewSize:] () #6 0x23dff6ee in __53-[__NSArrayM enumerateObjectsWithOptions:usingBlock:]_block_invoke () #7 0x23dff5ea in -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] () #8 0x2737a54a in -[UIView(Geometry) resizeSubviewsWithOldSize:] () #9 0x2746389c in -[UIView(AdditionalLayoutSupport) _is_layout] () #10 0x2760dbd4 in -[UIView(Hierarchy) _updateConstraintsAsNecessaryAndApplyLayoutFromEngine] () #11 0x27372b36 in -[UIView(CALayerDelegate) layoutSublayersOfLayer:] () #12 0x26d9accc in -[CALayer layoutSublayers] () #13 0x26d966b4 in CA::Layer::layout_if_needed(CA::Transaction*) () #14 0x26d9653c in CA::Layer::layout_and_display_if_needed(CA::Transaction*) () #15 0x26d95f20 in CA::Context::commit_transaction(CA::Transaction*) () #16 0x26d95d24 in CA::Transaction::commit() () #17 0x2736afc4 in _afterCACommitHandler () #18 0x23e9e5cc in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ () #19 0x23e9bc8a in __CFRunLoopDoObservers () #20 0x23e9c092 in __CFRunLoopRun () #21 0x23dea620 in CFRunLoopRunSpecific () #22 0x23dea432 in CFRunLoopRunInMode () #23 0x2b1980a8 in GSEventRunModal () #24 0x273d4808 in UIApplicationMain () #25 0x0003e3fc in main at /Users/me/Dev/MyApp/iosapp/MyApp/main.m:17
Here is the code that does the animating of the passed in self contained UI element, which is a self contained view controller and view which is implemented with a nib and auto layout for its internal composition.
The "inView" is the view passed in that should contain the UI element (parent view to the UI element). The "payPage" is the view controller for the self contained UI element.
CGRect payRect = CGRectMake(windowSize.width/2 - pageSize.width/2, windowSize.height/2 - pageSize.height/2 - offset, pageSize.width, pageSize.height);
UIGraphicsBeginImageContext(payPage.view.bounds.size);
[[[payPage view] layer] renderInContext:UIGraphicsGetCurrentContext()];
//[[payPage view] drawViewHierarchyInRect:payPage.view.bounds afterScreenUpdates:YES];// iOS8 issues with this -- jumps and flickers
UIImage *compositeImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *compositeImageView = [[UIImageView alloc] initWithImage:compositeImage];
[[payPage view] setAlpha:0.0f];
UIViewController *parentVC = [self visibleVC];
_parentVC = parentVC;
UIView *inView = [(MyStandardViewController *)parentVC localView];
CGRect middleRect = CGRectZero;
if (nil == fromView)
{
middleRect.origin = [[[UIApplication sharedApplication] keyWindow] center];
}
else
{
middleRect.origin = [[fromView superview] convertPoint:[fromView center] toView:inView];
}
[compositeImageView setFrame:middleRect];
_blockingView = [[UIView alloc] initWithFrame:[inView frame]];
[_blockingView setAlpha:0.0f];
[_blockingView setBackgroundColor:BLOCKINGVIEWBACKGROUNDCOLOR];
[inView addSubview:_blockingView];
[inView addSubview:compositeImageView];
[UIView animateWithDuration:2.25f animations:^{
[compositeImageView setFrame:payRect];
[_blockingView setAlpha:1.0f];
}
completion:^(BOOL finished) {
[inView addSubview:[payPage view]];
if (nil != parentVC)
{
[parentVC addChildViewController:payPage];
}
[[payPage view] setFrame:payRect];
[[payPage view] setAlpha:1.0f];
[compositeImageView removeFromSuperview];
}
];
I am not sure what to do. I have tried -setTranslatesAutoresizingMaskIntoConstraints:
on the parent view in various places with both YES and NO. I have looked at self contained UI elements (view controllers) that don't do this when added and don't see any obvious differences. I am not sure what avenue to be approaching on this since the code that does it is in auto layout and the app does not really consciously use auto layout except inside specific self contained view controllers.
In my case, I had a "hidden"
setTranslatesAutoresizingMaskIntoConstraints:NO
in the implementation of my subview that I had missed. Eliminating this made everything work the way it should.