-
Notifications
You must be signed in to change notification settings - Fork 250
ios-snapshot-test-case does not work properly if UIApperance attributes change intrinsic content size of view being tested #227
Description
I was having a problem regarding a view that wasn't being properly recorded when I changed an attribute of the view using the UIAppearance proxy, if that attribute would change the intrinsic content size of the view.
The culprit seems to be in the following method in UIImage+Snapshot.m:
+ (UIImage *)fb_imageForView:(UIView *)view
{
CGRect bounds = view.bounds;
NSAssert1(CGRectGetWidth(bounds), @"Zero width for view %@", view);
NSAssert1(CGRectGetHeight(bounds), @"Zero height for view %@", view);
// If the input view is already a UIWindow, then just use that. Otherwise wrap in a window.
UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *)view : view.window;
BOOL removeFromSuperview = NO;
if (!window) {
window = [[UIApplication sharedApplication] fb_strictKeyWindow];
}
if (!view.window && view != window) {
[window addSubview:view];
removeFromSuperview = YES;
}
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
[view layoutIfNeeded];
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if (removeFromSuperview) {
[view removeFromSuperview];
}
return snapshot;
}
The problem is the following:
- In the beginning of the method the current bounds of the view to be tested are stored in the
boundsvariable. - The view is added to a window (if it still didn't belong to one). This fires the appearance mechanism, that may set a property that calls
setNeedsLayout - Then an image context is created with the size of the original bounds.
- Then
layoutIfNeededis invoked on the view being tested. This may change the original dimensions of the view if the intrinsic content size changes - The view is drawn using its current bounds, but the image context is still using the original bounds
As a result, if the view has a greater intrinsic content size due to some change in appearance properties (for example, a greater font) it is clipped as it's being drawn in a smaller image context.
Is it possible to invoke layoutIfNedeedbefore UIGraphicsBeginImageContextWithOptions to use the updated size of the view? Or am I missing anything? BTW, the view I'm testing seems to be behaving correctly when resized after changing the font to a greater one in an application, so I think it's correctly implemented (I may share it if you want)