繁体   English   中英

SwiftUI:圆角 UIImage?

[英]SwiftUI: Round the corners of a UIImage?

我正在使用此扩展程序拍摄 SwiftUI 视图的图像(用于共享),但唯一的问题是我的视图的cornerRadius为 10.0,因此圆角,因此该图像最终以黑色非圆角结束,我如何获得摆脱它?

extension View {
  func takeScreenshot(origin: CGPoint, size: CGSize) -> UIImage? {

    // Get the main window.
    guard let window = UIApplication.shared.windows.first else {
      print("View.takeScreenshot: No main window found")
      return nil
    }

    // Create an image of the entire window. Note how we're using `window.bounds` for this
    // to capture the entire window.
    UIGraphicsBeginImageContextWithOptions(window.bounds.size, false, 0.0)
    let renderer = UIGraphicsImageRenderer(bounds: window.bounds, format: UIGraphicsImageRendererFormat())
    let image = renderer.image { (context) in
      window.drawHierarchy(in: window.bounds, afterScreenUpdates: true)
    }
    UIGraphicsEndImageContext()

    /*
    At this point we have a screenshot of the entire window.
    Now we're going to crop it to just include the part of the screen
    we want.
    */

    // Scale is the pixel density of the screen. E.g. 3.0 on iPhone 12 Pro which has a 3x display.
    // This will be used in the UIImage extension below.
    let scale = UIScreen.main.scale
    let rect = CGRect(x: origin.x, y: origin.y, width: size.width, height: size.height)
    let croppedImage = image.cropped(boundingBox: rect, scale: scale)
    
      
    return croppedImage
  }
}

extension UIImage {
  func cropped(boundingBox: CGRect, scale: CGFloat) -> UIImage? {

  /*
  To crop UIImage we must first convert it to a CGImage.
  UIImage uses points, which are independent of pixels.

  Therefore, we need to take the scaling factor of the screen into account
  when cropping.

  For example, if we want to crop a 100x50pt square starting at (75, 90) from a UIImage
  on a device with a 2x scaling factor, we would multiple everything by 2 and crop a
  200x100px square starting at (150, 180).
  */

    let x = boundingBox.origin.x * scale
    let y = boundingBox.origin.y * scale
    let width = boundingBox.width * scale
    let height = boundingBox.height * scale

    let adjustedBoundingBox = CGRect(x: x, y: y, width: width, height: height)

    guard let cgImage = self.cgImage?.cropping(to: adjustedBoundingBox) else {
      print("UIImage.cropped: Couldn't create cropped image")
      return nil
    }

    return UIImage(cgImage: cgImage)
  }
}

我正在截图的视图:

var shareCard: some View {
        VStack {
            Spacer()
            GeometryReader { geometry in
                if backgroundImage != UIImage() {
                    Image(uiImage: backgroundImage)
                        .resizable()
                        .scaledToFill()
                        .frame(width: geometry.size.width, height: geometry.size.height)
                        .clipped() //needed to add clipped otherwise the picture would go outside of the frame.  From https://sarunw.com/posts/how-to-resize-swiftui-image-and-keep-aspect-ratio/
                        .cornerRadius(10.0)
                        .overlay(
                            Color.black
                                .cornerRadius(10.0)
                                .opacity(0.45) //keep at 0.45?
                        )
                } else {
                    Image("sampleBackground")
                        .resizable()
                    //.scaledToFill()
                        .frame(width: geometry.size.width, height: geometry.size.height)
                        .cornerRadius(10.0)
                        .onAppear {
                            proxy = geometry
                        }
                }
            }
            Spacer()
        }
        .frame(height: 375)
        .padding(.horizontal)
        .overlay(
            TabView(selection: $selectedTabIndex) {
               //Omitted - these are views that are overlayed over the background or image and don't impact the size of the snapshot
               
            }
                .frame(height: 430)
                .padding(.horizontal)
                .tabViewStyle(.page(indexDisplayMode: isTakingSnapShot ? .never : .always))
                .overlay(
                    VStack {
                        switch shareType {
                        case .TodaySummary:
                            VStack {
                                HStack {
                                    HStack(alignment: .center) {
                                        Image("logo")
                                            .resizable()
                                            .aspectRatio(contentMode: .fit)
                                            .frame(height: 40)
                                            .padding(.leading)
                                        VStack(alignment: .leading, spacing: 3) {
                                            Text("AppName")
                                                .foregroundColor(.white)
                                                .font(.headline)
                                                .fontWeight(.bold)
                                           
                                            Text(Date(), style: .date)
                                                .foregroundColor(.white)
                                                .font(.footnote)
                                        }
                                    }
                                    Spacer()
                                }
                                .padding([.leading, .top])
                                Spacer()
                            }
                            .frame(height: 375)
                        case .Workout:
                            EmptyView() //Pass empty view here because we use a different header for workout share
                        }
                    }
                )
        )
        
    }

正如我在评论中所说,我对 SwiftUI 所做的工作很少——但是,这可能会帮助您继续前进。

使用运行此代码的代码:

在此处输入图像描述

点击红色按钮捕获并保存此图像:

在此处输入图像描述

我试图通过给主视图一个黄色背景来让它变得明显,这样我们就可以看到透明的圆角。 当然,您在页面上看不到它,但是如果您下载上面的图像(或运行以下代码并亲自尝试),您会看到它具有透明度。

您发布的代码中有太多未知数,因此我声明了自己的testCard视图。 一切都应该非常简单。

import SwiftUI

struct CaptureView: View {
    
    var testCard: some View {
        VStack {
            Spacer()
            GeometryReader { geometry in
                Image("sampleBackground")
                    .resizable()
                    .frame(width: geometry.size.width, height: geometry.size.height)
                    .cornerRadius(20.0)
            }
            Spacer()
        }
        .frame(width: 320, height: 240)
        .padding(.horizontal)
        .overlay(
            VStack {
                VStack {
                    HStack {
                        HStack(alignment: .center) {
                            Image("logo")
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                .frame(height: 40)
                                .padding(.leading)
                            VStack(alignment: .leading, spacing: 3) {
                                Text("AppName")
                                    .foregroundColor(.white)
                                    .font(.headline)
                                    .fontWeight(.bold)
                                
                                Text(Date(), style: .date)
                                    .foregroundColor(.white)
                                    .font(.footnote)
                            }
                        }
                        Spacer()
                    }
                    .padding([.leading, .top])
                    Spacer()
                }
                .frame(height: 220)
            }
        )
    }
    
    var body: some View {
        VStack {
            Spacer()
            Text("Tap red Button to capture view")
            Spacer()
            testCard
            Spacer()
            Button("Capture testCard View") {
                let img = testCard.snapshot(atSize: CGSize(width: 320.0, height: 240.0))
                saveImage(img)
            }
            .padding()
            .foregroundColor(.white)
            .background(Color.red)
            .cornerRadius(40)
            Spacer()
        }
        .background(Color(red: 1.0, green: 1.0, blue: 0.0))
    }
    
    func saveImage(_ img: UIImage) {
        var s: String = "Results:\n\n"
        
        let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        let fName: String = "testCard.png"
        let url = documents.appendingPathComponent(fName)
        if let data = img.pngData() {
            do {
                try data.write(to: url)
            } catch {
                s += "Unable to Write Image Data to Disk"
                print(s)
                return
            }
        } else {
            s += "Could not get png data"
            print(s)
            return
        }
        s += "Logical Size: \(img.size)\n"
        s += "Scale: \(img.scale)\n"
        s += "Actual Size: \(CGSize(width: img.size.width * img.scale, height: img.size.height * img.scale))\n"
        s += "File \"\(fName)\" saved to Documents folder\n"
        print(s)

        // print the path to documents in debug console
        //  so we can copy/paste into Finder to get to the files
        print(documents.path)

    }
}

extension View {
    // if view HAS a valid .intrinsicContentSize
    func snapshot() -> UIImage {
        let controller = UIHostingController(rootView: self)
        let view = controller.view
        
        let targetSize = controller.view.intrinsicContentSize
        view?.bounds = CGRect(origin: .zero, size: targetSize)
        view?.backgroundColor = .clear
        
        let renderer = UIGraphicsImageRenderer(size: targetSize)
        
        return renderer.image { _ in
            view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
        }
    }
    // specify size to save
    func snapshot(atSize targetSize: CGSize) -> UIImage {
        let controller = UIHostingController(rootView: self, ignoreSafeArea: true)
        let view = controller.view
        
        view?.bounds = CGRect(origin: .zero, size: targetSize)
        view?.backgroundColor = .clear
        
        let renderer = UIGraphicsImageRenderer(size: targetSize)
        
        return renderer.image { _ in
            view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
        }
    }
}
// extension to remove safe area from UIHostingController
//  source: https://stackoverflow.com/a/70339424/6257435
extension UIHostingController {
    convenience public init(rootView: Content, ignoreSafeArea: Bool) {
        self.init(rootView: rootView)
        
        if ignoreSafeArea {
            disableSafeArea()
        }
    }
    
    func disableSafeArea() {
        guard let viewClass = object_getClass(view) else { return }
        
        let viewSubclassName = String(cString: class_getName(viewClass)).appending("_IgnoreSafeArea")
        if let viewSubclass = NSClassFromString(viewSubclassName) {
            object_setClass(view, viewSubclass)
        }
        else {
            guard let viewClassNameUtf8 = (viewSubclassName as NSString).utf8String else { return }
            guard let viewSubclass = objc_allocateClassPair(viewClass, viewClassNameUtf8, 0) else { return }
            
            if let method = class_getInstanceMethod(UIView.self, #selector(getter: UIView.safeAreaInsets)) {
                let safeAreaInsets: @convention(block) (AnyObject) -> UIEdgeInsets = { _ in
                    return .zero
                }
                class_addMethod(viewSubclass, #selector(getter: UIView.safeAreaInsets), imp_implementationWithBlock(safeAreaInsets), method_getTypeEncoding(method))
            }
            
            objc_registerClassPair(viewSubclass)
            object_setClass(view, viewSubclass)
        }
    }
}

struct CaptureView_Previews: PreviewProvider {
    static var previews: some View {
        CaptureView()
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM