Skip to content
This repository was archived by the owner on Jan 13, 2022. It is now read-only.

ios-snapshot-test-case does not work properly if UIApperance attributes change intrinsic content size of view being tested #227

@jgongo

Description

@jgongo

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:

  1. In the beginning of the method the current bounds of the view to be tested are stored in the bounds variable.
  2. 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
  3. Then an image context is created with the size of the original bounds.
  4. Then layoutIfNeeded is invoked on the view being tested. This may change the original dimensions of the view if the intrinsic content size changes
  5. 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions