UIView的snapshotView在没有任何内容的情况下渲染/绘制

ooO*_*lly 4 iphone objective-c uiview uiimage ios

我正在尝试在上下文中渲染/绘制UIView的snapshotView以获取UIImage.然后将其设置为CAlayer.contents.我尝试这个方法来获取snapshotView:

snapshotViewAfterScreenUpdates:
Run Code Online (Sandbox Code Playgroud)

然后将UIView转换为UIImage:

UIGraphicsBeginImageContext(view.bounds.size);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
//I'm trying this method too
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Run Code Online (Sandbox Code Playgroud)

问题是我正在使用上面的代码,但我得到一个空图像.

dop*_*pcn 6

如果您首先需要快照UIImage,只需使用第二个代码块中的方法即可.创建一个UIView的类别

@implementation UIView (takeSnapshot)

- (UIImage *)takeASnapshot {
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);

    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

@end
Run Code Online (Sandbox Code Playgroud)

这就够了.您不需要对视图进行快照并将其转换为图像.在您的情况下,此过程可能会导致问题

  • Apple'doc:**如果要将快速图形效果(如模糊)应用于快照,请改用drawViewHierarchyInRect:afterScreenUpdates:方法.** (2认同)

Vla*_*lad 6

使用floating snapshots. 在这里我们做了什么:

UIView 扩展:

extension UIView {

   public func snapshot(scale: CGFloat = 0, isOpaque: Bool = false, afterScreenUpdates: Bool = true) -> UIImage? {
      UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, scale)
      drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
      let image = UIGraphicsGetImageFromCurrentImageContext()
      UIGraphicsEndImageContext()
      return image
   }


   public enum CASnapshotLayer: Int {
      case `default`, presentation, model
   }

   /// The method drawViewHierarchyInRect:afterScreenUpdates: performs its operations on the GPU as much as possible
   /// In comparison, the method renderInContext: performs its operations inside of your app’s address space and does
   /// not use the GPU based process for performing the work.
   /// /sf/answers/1799340301/
   public func caSnapshot(scale: CGFloat = 0, isOpaque: Bool = false,
                          layer layerToUse: CASnapshotLayer = .default) -> UIImage? {
      var isSuccess = false
      UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, scale)
      if let context = UIGraphicsGetCurrentContext() {
         isSuccess = true
         switch layerToUse {
         case .default:
            layer.render(in: context)
         case .model:
            layer.model().render(in: context)
         case .presentation:
            layer.presentation()?.render(in: context)
         }
      }
      let image = UIGraphicsGetImageFromCurrentImageContext()
      UIGraphicsEndImageContext()
      return isSuccess ? image : nil
   }
}
Run Code Online (Sandbox Code Playgroud)

使用示例(交互动画内部):

private func makeSnapshot(view: UIView, snapshotLayer: UIView.CASnapshotLayer) -> UIView? {
   // There is 3 ways for taking snapshot:
   // 1. Replicate view: `view.snapshotView(afterScreenUpdates: true)`
   // 2. Draw Hierarchy: `view.drawHierarchy(in: bounds, afterScreenUpdates: true)`
   // 3. Render Layer: `layer.render(in: context)`
   //
   // Only #3 is working reliable during UINavigation controller animated transitions.
   // For modally presented UI also trick by combining #1 and #2 seems works.
   // I.e. `view.snapshotView(afterScreenUpdates: true).snapshot()`
   //
   // If this call causes error listed below, then this indicate that something wrong with one of the views layout.
   // [Snapshotting] View (_UIReplicantView) drawing with afterScreenUpdates:YES inside CoreAnimation commit is not supported.
   // See also: /sf/answers/2077334521/
   if let image = view.caSnapshot(layer: snapshotLayer) {
      let imageView = ImageView(image: image)
      imageView.clipsToBounds = true
      imageView.contentMode = .scaleAspectFit
      shapshots[view] = image
      return imageView
   }
   return nil
}
Run Code Online (Sandbox Code Playgroud)

  • 哇,多么好的解决方案啊。已在 Swift 5 上测试并运行 (2认同)