gre / react-native-view-shot

Snapshot a React Native view and save it to an image
https://github.com/gre/react-native-view-shot-example
MIT License
2.66k stars 346 forks source link

4.0.0-alpha.3 ios snapshot wrong #539

Open MmyzFlowerDog opened 3 months ago

MmyzFlowerDog commented 3 months ago

RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber )target withOptions:(NSDictionary )options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager uiManager, NSDictionary<NSNumber , UIView > viewRegistry) {

// Get view
UIView *view;

if ([target intValue] == -1) {
  UIWindow *window = [[UIApplication sharedApplication] keyWindow];
  view = window;
} else {
  view = viewRegistry[target];
}

if (!view) {
  reject(RCTErrorUnspecified, [NSString stringWithFormat:@"No view found with reactTag: %@", target], nil);
  return;
}

// Get options
CGSize size = [RCTConvert CGSize:options];
NSString *format = [RCTConvert NSString:options[@"format"]];
NSString *result = [RCTConvert NSString:options[@"result"]];
BOOL renderInContext = [RCTConvert BOOL:options[@"useRenderInContext"]];
BOOL snapshotContentContainer = [RCTConvert BOOL:options[@"snapshotContentContainer"]];

// Capture image
BOOL success;

UIView* rendered;
UIScrollView* scrollView;
if (snapshotContentContainer) {
  if (![view isKindOfClass:[RCTScrollView class]]) {
    reject(RCTErrorUnspecified, [NSString stringWithFormat:@"snapshotContentContainer can only be used on a RCTScrollView. instead got: %@", view], nil);
    return;
  }
  RCTScrollView* rctScrollView = view;
  scrollView = rctScrollView.scrollView;
  rendered = scrollView;
}
else {
  rendered = view;
}

if (size.width < 0.1 || size.height < 0.1) {
  size = snapshotContentContainer ? scrollView.contentSize : view.bounds.size;
}
if (size.width < 0.1 || size.height < 0.1) {
  reject(RCTErrorUnspecified, [NSString stringWithFormat:@"The content size must not be zero or negative. Got: (%g, %g)", size.width, size.height], nil);
  return;
}

CGPoint savedContentOffset;
CGRect savedFrame;
if (snapshotContentContainer) {
  // Save scroll & frame and set it temporarily to the full content size
  savedContentOffset = scrollView.contentOffset;
  savedFrame = scrollView.frame;
  scrollView.contentOffset = CGPointZero;
  scrollView.frame = CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height);
}

UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size];

if (renderInContext) {
  // this comes with some trade-offs such as inability to capture gradients or scrollview's content in full but it works for large views
  [rendered.layer renderInContext: UIGraphicsGetCurrentContext()];
  success = YES;
}
else {
  // this doesn't work for large views and reports incorrect success even though the image is blank
  success = [rendered drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
}

UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {}];

if (snapshotContentContainer) {
  // Restore scroll & frame
  scrollView.contentOffset = savedContentOffset;
  scrollView.frame = savedFrame;
}


In this method, " UIImage image = [renderer imageWithActions:^(UIGraphicsImageRendererContext _Nonnull rendererContext) {}];" should be " UIImage image = [renderer imageWithActions:^(UIGraphicsImageRendererContext _Nonnull rendererContext) { [rendered.layer renderInContext:rendererContext.CGContext]; }];" , or it will make the image become empty white in IOS17,