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

Commit 740e14c

Browse files
author
Patrick Chamelo
committed
Merge pull request #100 from facebook/nscoding/visualeffects
Option to use usesDrawViewHierarchyInRect:afterScreenUpdates:
2 parents 318ac6c + 5a93d5e commit 740e14c

23 files changed

Lines changed: 122 additions & 68 deletions

File tree

FBSnapshotTestCase/Categories/UIImage+Snapshot.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212

1313
@interface UIImage (Snapshot)
1414

15-
+ (UIImage *)fb_imageForViewOrLayer:(id)viewOrLayer;
15+
/// Uses renderInContext: to get a snapshot of the layer.
16+
+ (UIImage *)fb_imageForLayer:(CALayer *)layer;
17+
18+
/// Uses renderInContext: to get a snapshot of the view layer.
19+
+ (UIImage *)fb_imageForViewLayer:(UIView *)view;
20+
21+
/// Uses drawViewHierarchyInRect: to get a snapshot of the view and adds the view into a window if needed.
22+
+ (UIImage *)fb_imageForView:(UIView *)view;
1623

1724
@end

FBSnapshotTestCase/Categories/UIImage+Snapshot.m

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,6 @@
1212

1313
@implementation UIImage (Snapshot)
1414

15-
+ (UIImage *)fb_imageForViewOrLayer:(id)viewOrLayer
16-
{
17-
if ([viewOrLayer isKindOfClass:[UIView class]]) {
18-
return [self fb_imageForView:viewOrLayer];
19-
} else if ([viewOrLayer isKindOfClass:[CALayer class]]) {
20-
CALayer *layer = (CALayer *)viewOrLayer;
21-
[layer layoutIfNeeded];
22-
return [self fb_imageForLayer:layer];
23-
} else {
24-
[NSException raise:@"Only UIView and CALayer classes can be snapshotted" format:@"%@", viewOrLayer];
25-
}
26-
return nil;
27-
}
28-
2915
+ (UIImage *)fb_imageForLayer:(CALayer *)layer
3016
{
3117
CGRect bounds = layer.bounds;
@@ -35,8 +21,8 @@ + (UIImage *)fb_imageForLayer:(CALayer *)layer
3521
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
3622
CGContextRef context = UIGraphicsGetCurrentContext();
3723
NSAssert1(context, @"Could not generate context for layer %@", layer);
38-
3924
CGContextSaveGState(context);
25+
[layer layoutIfNeeded];
4026
[layer renderInContext:context];
4127
CGContextRestoreGState(context);
4228

@@ -45,10 +31,32 @@ + (UIImage *)fb_imageForLayer:(CALayer *)layer
4531
return snapshot;
4632
}
4733

48-
+ (UIImage *)fb_imageForView:(UIView *)view
34+
+ (UIImage *)fb_imageForViewLayer:(UIView *)view
4935
{
5036
[view layoutIfNeeded];
5137
return [self fb_imageForLayer:view.layer];
5238
}
5339

40+
+ (UIImage *)fb_imageForView:(UIView *)view
41+
{
42+
CGRect bounds = view.bounds;
43+
NSAssert1(CGRectGetWidth(bounds), @"Zero width for view %@", view);
44+
NSAssert1(CGRectGetHeight(bounds), @"Zero height for view %@", view);
45+
46+
UIWindow *window = view.window;
47+
if (window == nil) {
48+
window = [[UIWindow alloc] initWithFrame:bounds];
49+
[window addSubview:view];
50+
[window makeKeyAndVisible];
51+
}
52+
53+
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
54+
[view layoutIfNeeded];
55+
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
56+
57+
UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
58+
UIGraphicsEndImageContext();
59+
return snapshot;
60+
}
61+
5462
@end

FBSnapshotTestCase/FBSnapshotTestCase.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,17 @@ FBSnapshotVerifyLayerWithOptions(layer__, identifier__, FBSnapshotTestCaseDefaul
9494
*/
9595
@property (readwrite, nonatomic, assign) BOOL recordMode;
9696

97+
/**
98+
When YES, renders a snapshot of the complete view hierarchy as visible onscreen.
99+
There are several things that do not work if renderInContext: is used.
100+
- UIVisualEffect #70
101+
- UIApperance #91
102+
- Size Classes #92
103+
104+
@attention If the view does't belong to a UIWindow, it will create one and add the view as a subview.
105+
*/
106+
@property (readwrite, nonatomic, assign) BOOL usesDrawViewHierarchyInRect;
107+
97108
- (void)setUp NS_REQUIRES_SUPER;
98109
- (void)tearDown NS_REQUIRES_SUPER;
99110

FBSnapshotTestCase/FBSnapshotTestCase.m

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ - (void)setRecordMode:(BOOL)recordMode
4141
_snapshotController.recordMode = recordMode;
4242
}
4343

44+
- (BOOL)usesDrawViewHierarchyInRect
45+
{
46+
return _snapshotController.usesDrawViewHierarchyInRect;
47+
}
48+
49+
- (void)setUsesDrawViewHierarchyInRect:(BOOL)usesDrawViewHierarchyInRect
50+
{
51+
NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__);
52+
_snapshotController.usesDrawViewHierarchyInRect = usesDrawViewHierarchyInRect;
53+
}
54+
4455
#pragma mark - Public API
4556

4657
- (BOOL)compareSnapshotOfLayer:(CALayer *)layer

FBSnapshotTestCase/FBSnapshotTestController.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,14 @@ extern NSString *const FBReferenceImageFilePathKey;
3737

3838
/**
3939
Record snapshots.
40-
**/
40+
*/
4141
@property (readwrite, nonatomic, assign) BOOL recordMode;
4242

43+
/**
44+
Uses drawViewHierarchyInRect:afterScreenUpdates: to draw the image instead of renderInContext:
45+
*/
46+
@property (readwrite, nonatomic, assign) BOOL usesDrawViewHierarchyInRect;
47+
4348
/**
4449
The directory in which referfence images are stored.
4550
*/

FBSnapshotTestCase/FBSnapshotTestController.m

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ - (BOOL)_performPixelComparisonWithViewOrLayer:(id)viewOrLayer
268268
{
269269
UIImage *referenceImage = [self referenceImageForSelector:selector identifier:identifier error:errorPtr];
270270
if (nil != referenceImage) {
271-
UIImage *snapshot = [UIImage fb_imageForViewOrLayer:viewOrLayer];
271+
UIImage *snapshot = [self _imageForViewOrLayer:viewOrLayer];
272272
BOOL imagesSame = [self compareReferenceImage:referenceImage toImage:snapshot tolerance:tolerance error:errorPtr];
273273
if (!imagesSame) {
274274
[self saveFailedReferenceImage:referenceImage
@@ -287,7 +287,7 @@ - (BOOL)_recordSnapshotOfViewOrLayer:(id)viewOrLayer
287287
identifier:(NSString *)identifier
288288
error:(NSError **)errorPtr
289289
{
290-
UIImage *snapshot = [UIImage fb_imageForViewOrLayer:viewOrLayer];
290+
UIImage *snapshot = [self _imageForViewOrLayer:viewOrLayer];
291291
return [self _saveReferenceImage:snapshot selector:selector identifier:identifier error:errorPtr];
292292
}
293293

@@ -329,4 +329,20 @@ - (BOOL)_saveReferenceImage:(UIImage *)image
329329
return didWrite;
330330
}
331331

332+
- (UIImage *)_imageForViewOrLayer:(id)viewOrLayer
333+
{
334+
if ([viewOrLayer isKindOfClass:[UIView class]]) {
335+
if (_usesDrawViewHierarchyInRect) {
336+
return [UIImage fb_imageForView:viewOrLayer];
337+
} else {
338+
return [UIImage fb_imageForViewLayer:viewOrLayer];
339+
}
340+
} else if ([viewOrLayer isKindOfClass:[CALayer class]]) {
341+
return [UIImage fb_imageForLayer:viewOrLayer];
342+
} else {
343+
[NSException raise:@"Only UIView and CALayer classes can be snapshotted" format:@"%@", viewOrLayer];
344+
}
345+
return nil;
346+
}
347+
332348
@end

FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo.xcodeproj/project.pbxproj

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
B30449221AB794320067C75D /* FBSnapshotTestCaseDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B30449211AB794320067C75D /* FBSnapshotTestCaseDemoTests.m */; };
1313
B30449351AB795230067C75D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B304492C1AB795230067C75D /* InfoPlist.strings */; };
1414
B30449361AB795230067C75D /* FBAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B304492F1AB795230067C75D /* FBAppDelegate.m */; };
15-
B30449371AB795230067C75D /* FBExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = B30449311AB795230067C75D /* FBExampleView.m */; };
1615
B30449381AB795230067C75D /* FBSnapshotTestCaseDemo-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B30449321AB795230067C75D /* FBSnapshotTestCaseDemo-Info.plist */; };
1716
B30449391AB795230067C75D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B30449341AB795230067C75D /* Images.xcassets */; };
1817
F02D88451B1F246300BFBC1D /* FBSnapshotTestCaseSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F02D88441B1F246300BFBC1D /* FBSnapshotTestCaseSwiftTests.swift */; };
@@ -40,8 +39,6 @@
4039
B304492D1AB795230067C75D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = InfoPlist.strings; sourceTree = "<group>"; };
4140
B304492E1AB795230067C75D /* FBAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBAppDelegate.h; sourceTree = "<group>"; };
4241
B304492F1AB795230067C75D /* FBAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBAppDelegate.m; sourceTree = "<group>"; };
43-
B30449301AB795230067C75D /* FBExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBExampleView.h; sourceTree = "<group>"; };
44-
B30449311AB795230067C75D /* FBExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBExampleView.m; sourceTree = "<group>"; };
4542
B30449321AB795230067C75D /* FBSnapshotTestCaseDemo-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "FBSnapshotTestCaseDemo-Info.plist"; sourceTree = "<group>"; };
4643
B30449331AB795230067C75D /* FBSnapshotTestCaseDemo-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FBSnapshotTestCaseDemo-Prefix.pch"; sourceTree = "<group>"; };
4744
B30449341AB795230067C75D /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
@@ -103,8 +100,6 @@
103100
B304492B1AB795230067C75D /* en.lproj */,
104101
B304492E1AB795230067C75D /* FBAppDelegate.h */,
105102
B304492F1AB795230067C75D /* FBAppDelegate.m */,
106-
B30449301AB795230067C75D /* FBExampleView.h */,
107-
B30449311AB795230067C75D /* FBExampleView.m */,
108103
B30449321AB795230067C75D /* FBSnapshotTestCaseDemo-Info.plist */,
109104
B30449331AB795230067C75D /* FBSnapshotTestCaseDemo-Prefix.pch */,
110105
B30449341AB795230067C75D /* Images.xcassets */,
@@ -307,7 +302,6 @@
307302
isa = PBXSourcesBuildPhase;
308303
buildActionMask = 2147483647;
309304
files = (
310-
B30449371AB795230067C75D /* FBExampleView.m in Sources */,
311305
B30449361AB795230067C75D /* FBAppDelegate.m in Sources */,
312306
B30449081AB794320067C75D /* main.m in Sources */,
313307
);

FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/FBExampleView.h

Lines changed: 0 additions & 15 deletions
This file was deleted.

FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/FBExampleView.m

Lines changed: 0 additions & 21 deletions
This file was deleted.

FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/Images.xcassets/AppIcon.appiconset/Contents.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
"idiom" : "iphone",
1515
"size" : "60x60",
1616
"scale" : "2x"
17+
},
18+
{
19+
"idiom" : "iphone",
20+
"size" : "60x60",
21+
"scale" : "3x"
1722
}
1823
],
1924
"info" : {

0 commit comments

Comments
 (0)