วิธีแปลง UIView เป็นรูปภาพ


99

ฉันต้องการแปลง UIView เป็นรูปภาพและบันทึกไว้ในแอพของฉัน ใครช่วยบอกวิธีถ่ายภาพหน้าจอหรือแปลงเป็นภาพและวิธีที่ดีที่สุดในการบันทึกลงในแอปคืออะไร (ไม่ใช่ม้วนฟิล์ม) นี่คือรหัสสำหรับมุมมอง:

var overView   = UIView(frame: CGRectMake(0, 0, self.view.frame.width/1.3, self.view.frame.height/1.3))
overView.center = CGPointMake(CGRectGetMidX(self.view.bounds),
CGRectGetMidY(self.view.bounds)-self.view.frame.height/16);
overView.backgroundColor = UIColor.whiteColor()
self.view.addSubview(overView)
self.view.bringSubviewToFront(overView)

ที่เกี่ยวข้อง: stackoverflow.com/q/59592933/294884
Fattie

คำตอบ:


199

ส่วนขยายUIViewควรทำเคล็ดลับ

extension UIView {

    // Using a function since `var image` might conflict with an existing variable
    // (like on `UIImageView`)
    func asImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in
            layer.render(in: rendererContext.cgContext)
        }
    }
}

Apple ไม่สนับสนุนการUIGraphicsBeginImageContextเริ่มต้น iOS 10 ด้วยการเปิดตัวขอบเขตสี P3 UIGraphicsBeginImageContextเป็น sRGB และ 32 บิตเท่านั้น พวกเขาเปิดตัวUIGraphicsImageRendererAPI ใหม่ที่มีการจัดการสีโดยสมบูรณ์แบบบล็อกมีคลาสย่อยสำหรับ PDF และรูปภาพและจัดการอายุการใช้งานบริบทโดยอัตโนมัติ ตรวจสอบเซสชัน WWDC16 205สำหรับรายละเอียดเพิ่มเติม (การเรนเดอร์ภาพเริ่มต้นประมาณเครื่องหมาย 11:50)

เพื่อให้แน่ใจว่าใช้งานได้กับทุกอุปกรณ์ให้ใช้#availableกับ iOS เวอร์ชันก่อนหน้านี้

extension UIView {

    // Using a function since `var image` might conflict with an existing variable
    // (like on `UIImageView`)
    func asImage() -> UIImage {
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(bounds: bounds)
            return renderer.image { rendererContext in
                layer.render(in: rendererContext.cgContext)
            }
        } else {
            UIGraphicsBeginImageContext(self.frame.size)
            self.layer.render(in:UIGraphicsGetCurrentContext()!)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return UIImage(cgImage: image!.cgImage!)
        }
    }
}

9
ควรทำเครื่องหมายว่าเป็นคำตอบที่ถูกต้อง ตัวเลือกอื่น ๆ ทั้งหมดจะทำให้ภาพที่เรนเดอร์สูญเสียความชัดเจนและดูเป็นพิกเซล / เบลอ
TuplingD

วิธีเดียวที่ถูกต้อง! สำหรับผู้เริ่มต้นการใช้งานคือ: let image = customView.asImage ()
Fabio

1
เป็นไปได้ไหมที่จะแสดง UIView ด้วยพื้นหลังโปร่งใส? เหมืองมีมุมโค้งมน
ixany

@ixany นี่ควรดูแลมันอยู่แล้ว ฉันเพิ่งลองใช้สิ่งต่อไปนี้ในสนามเด็กเล่นและใช้งานได้: let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)); view.backgroundColor = .black; view.layer.cornerRadius = 9; view.asImage();
Naveed J.

2
ขอบคุณ! ถ้าใครรู้คงอยากรู้ว่าโค้ดจากhackingwithswift.com/example-code/media/… : return renderer.image {ctx in drawHierarchy (in: bounds, afterScreenUpdates: true)}
Kqtr

64

คุณสามารถใช้นามสกุล

extension UIImage {
    convenience init(view: UIView) {
        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in:UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: image!.cgImage!)
    }
}

นี่คือรุ่น 3/4 ที่รวดเร็ว:

extension UIImage {
    convenience init(view: UIView) {
        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in:UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: image!.cgImage!)
    }
}

5
ฉันอายที่เป็นคนถามแบบนี้ แต่ฉันจะเรียกแบบนี้ได้อย่างไร ฉันไม่มีภาพและ UIView ที่ฉันต้องการให้เป็นภาพ รหัสด้านบนให้ส่วนขยาย UIImage แก่ฉัน ... แต่ตอนนี้เป็นอย่างไร
Dave G

8
let image = UIImage(view: myView)
doctorBroctor

ไม่ทำงานสำหรับฉันเนื่องจาก UIGraphicsGetCurrentContext () อาจเป็นศูนย์และโค้ดขัดข้อง
Juan Carlos Ospina Gonzalez

@JuanCarlosOspinaGonzalez ถ้า UIGraphicsGetCurrentContext คืนค่าศูนย์ฉันสงสัยว่าคุณต้องตรวจสอบ UIGraphicsBeginImageContext เพื่อดูว่าทำไมจึงล้มเหลว ฉันเดาว่ามิติหนึ่งของขนาดของคุณเป็นศูนย์หรือไม่ถูกต้อง แต่ฉันไม่รู้ว่าอะไรจะทำให้มันล้มเหลวได้
John Stephen

2
คุณควรจำขนาดของหน้าจอด้วยดังนั้นฉันจะแทนที่บรรทัดแรกของตัวเริ่มต้นด้วยสิ่งนี้: UIGraphicsBeginImageContextWithOptions(view.frame.size, false, UIScreen.main.scale)
iVentis

41

แปลง UIView ของคุณเป็นรูปภาพโดยdrawViewHierarchyInRect: afterScreenUpdates:ซึ่งเร็วกว่า renderInContext หลายเท่า

หมายเหตุสำคัญ: อย่าเรียกใช้ฟังก์ชันนี้จากviewDidLoad หรือ viewWillAppearตรวจสอบให้แน่ใจว่าคุณกำลังจับภาพมุมมองหลังจากที่แสดง / โหลดเต็มที่แล้ว

Obj C.

     UIGraphicsBeginImageContextWithOptions(myView.bounds.size, myView.opaque, 0.0f);
     [myView drawViewHierarchyInRect:myView.bounds afterScreenUpdates:NO];
     UIImage *snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();

     myImageView.image =  snapshotImageFromMyView;

บันทึกรูปภาพที่แก้ไขอัลบั้มรูปภาพ

     UIImageWriteToSavedPhotosAlbum(snapshotImageFromMyView, nil,nil, nil);

สวิฟต์ 3/4

    UIGraphicsBeginImageContextWithOptions(myView.bounds.size, myView.isOpaque, 0.0)
    myView.drawHierarchy(in: myView.bounds, afterScreenUpdates: false)
    let snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    print(snapshotImageFromMyView)
    myImageView.image = snapshotImageFromMyView

การวางนัยทั่วไปที่ง่ายสุด ๆ พร้อมส่วนขยาย iOS11, swift3 / 4

extension UIImage{
    convenience init(view: UIView) {

    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
    view.drawHierarchy(in: view.bounds, afterScreenUpdates: false)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    self.init(cgImage: (image?.cgImage)!)

  }
}


Use : 
 //myView is completly loaded/visible , calling this code after only after viewDidAppear is call
 imgVV.image = UIImage.init(view: myView)
 // Simple image object
 let img =  UIImage.init(view: myView)

3
ไม่ทำงานสำหรับฉันฉันมี blackScreen สำหรับ UiImage ของฉัน
Badr Filali

เหรอ ?? คุณสามารถวางรหัสของคุณที่นี่ได้ไหม .. คุณอาจใช้วัตถุ UIView ที่ไม่ถูกต้องเพื่อแปลงเป็น UIImage
ViJay Avhad

`func convertViewIntoImg () -> Void {imgFakeCard.image = UIImage.init (view: card)}` ด้วยส่วนขยายของคุณใน swift 3 ฟังก์ชันนี้เรียกว่าใน viewDidLoad
Badr Filali

1
ขอขอบคุณที่โพสต์รหัสของคุณและแจ้งว่าคุณได้โทรเข้า viewDidLoad นี่คือสิ่งที่คุณผิดพลาด คุณกำลังบันทึกภาพรวมของมุมมองก่อนที่จะโหลดในหน่วยความจำ โปรดลองโทรหารหัสใน viewDidAppear ซึ่งจะช่วยแก้ปัญหาได้อย่างแน่นอน คำถามใด ๆ โปรดตอบกลับ
ViJay Avhad

ขอบคุณมากที่ได้ผลปัญหามาจากที่ฉันเรียกส่วนขยายของคุณ
Badr Filali

20

บน iOS 10:

extension UIImage {
    convenience init(view: UIView) {
        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: (image?.cgImage)!)
    }
}

1
สิ่งนี้นำไปสู่การขัดข้อง
KingPolygon

18

แนวทางปฏิบัติที่ดีที่สุดสำหรับ iOS 10 และ Swift 3

ในขณะที่ยังรองรับ iOS 9 และรุ่นก่อนหน้า ยังคงใช้งานได้เหมือน iOS 13, Xcode 11.1, Swift 5.1

extension UIView {

    func asImage() -> UIImage? {
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(bounds: bounds)
            return renderer.image { rendererContext in
                layer.render(in: rendererContext.cgContext)
            }
        } else {
            UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0)
            defer { UIGraphicsEndImageContext() }
            guard let currentContext = UIGraphicsGetCurrentContext() else {
                return nil
            }
            self.layer.render(in: currentContext)
            return UIGraphicsGetImageFromCurrentImageContext()
        }
    }
}

ฉันไม่แน่ใจว่าคำถามหมายถึงอะไรโดย:

วิธีใดดีที่สุดในการบันทึกลงในแอป (ไม่ใช่ม้วนฟิล์ม)


17
    UIGraphicsBeginImageContext(self.view.bounds.size);        
    self.view.layer.renderInContext(UIGraphicsGetCurrentContext())
    var screenShot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();


1
UIGraphicsGetImageFromCurrentImageContext ส่งคืน UIImage ไม่ต้องแคสต์ลง UIImage
Leo Dabus

นี่จับภาพหน้าจอของมุมมองทั้งหมดใช่ไหม ฉันแค่ต้องการแปลงภาพรวม UIView ie ในโค้ดของฉันซึ่งเป็น subview ของ self.view เป็นรูปภาพ ไม่ใช่มุมมองทั้งหมด!
Sameer Hussain

@Vakas เมื่อฉันพยายามพิมพ์ภาพมันแสดงผลเล็กเกินไปทางออกสำหรับสิ่งนี้คืออะไร
Krutarth Patel

6
ภาพหน้าจอไม่มีคุณภาพดีควรทำอย่างไร?
Neela

13

ตัวอย่างเช่นหากฉันมีมุมมองขนาด: 50 50 ที่ 100,100 ฉันสามารถใช้สิ่งต่อไปนี้เพื่อถ่ายภาพหน้าจอ:

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), false, 0);
    self.view.drawViewHierarchyInRect(CGRectMake(-50,-5-,view.bounds.size.width,view.bounds.size.height), afterScreenUpdates: true)
    var image:UIImage = UIGraphicsGetImageFromCurrentImageContext();

ในบรรทัด self.view มีความผิดพลาดในพารามิเตอร์ฉันคิดว่าควรเป็น -5 ไม่ใช่ -5-
Krutarth Patel

@sameer ฉันมีคำถามหนึ่งข้อเมื่อฉันพิมพ์ภาพนี้มีขนาดเล็กเกินไป
Krutarth Patel

7

ในความคิดของฉันวิธีการกับตัวเริ่มต้นนั้นไม่ค่อยดีนักเพราะมันสร้างภาพสองภาพ

ฉันชอบสิ่งนี้:

extension UIView {
    var snapshot: UIImage? {
        UIGraphicsBeginImageContext(self.frame.size)
        guard let context = UIGraphicsGetCurrentContext() else {
            return nil
        }
        layer.render(in: context)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

คุณควรเรียกทรัพย์สินอย่างอื่นที่ไม่ใช่รูปภาพ สิ่งนี้สามารถรบกวนคลาสย่อยที่มีคุณสมบัติที่เรียกว่ารูปภาพเช่น UIImageView
Hobbes the Tige

ปฏิบัติตามข้อเสนอแนะของ @HobbestheTige และเปลี่ยนชื่อสถานที่ให้บริการ
Tino

6

Swift 4.2, iOS 10

extension UIView {

    // If Swift version is lower than 4.2, 
    // You should change the name. (ex. var renderedImage: UIImage?)

    var image: UIImage? {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) }
    }
}

ตัวอย่าง

let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.backgroundColor = .blue

let view2 = UIView(frame: CGRect(x: 10, y: 10, width: 20, height: 20))
view2.backgroundColor = .red
view.addSubview(view2)

let imageView = UIImageView(image: view.image)

ป้อนคำอธิบายภาพที่นี่


แค่อยากจะชี้ให้เห็นว่าสิ่งนี้จำเป็นต้องตั้งชื่ออย่างอื่นหากคุณใช้ UIImageView ในโปรเจ็กต์ของคุณมิฉะนั้นรูปภาพจะกลายเป็นแบบอ่านอย่างเดียว อาจเรียกมันว่า 'screenCapture' แทน 'image'
คริส

@ คริสใช่คุณพูดถูก คุณควรเปลี่ยนชื่อหากเวอร์ชัน Swift ต่ำกว่า 4.2 ขอขอบคุณที่ชี้ให้เห็นข้อผิดพลาด
Den

6

สิ่งนี้ใช้ได้กับฉันสำหรับXcode 9 / Swift 3.2 / Swift 4และXcode 8 / Swift 3

 if #available(iOS 10.0, *) {

     // for Xcode 9/Swift 3.2/Swift 4 -Paul Hudson's code
     let renderer = UIGraphicsImageRenderer(size: view!.bounds.size)
     let capturedImage = renderer.image { 
         (ctx) in
         view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: true)
     }
     return capturedImage

 } else {

     // for Xcode 8/Swift 3
     UIGraphicsBeginImageContextWithOptions((view!.bounds.size), view!.isOpaque, 0.0)
     view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: false)
     let capturedImage = UIGraphicsGetImageFromCurrentImageContext()
     UIGraphicsEndImageContext()
     return capturedImage!
 }

นี่คือวิธีการใช้งานภายในฟังก์ชัน:

fileprivate func captureUIImageFromUIView(_ view:UIView?) -> UIImage {

     guard (view != nil) else{

        // if the view is nil (it's happened to me) return an alternative image
        let errorImage = UIImage(named: "Error Image")
        return errorImage
     }

     // if the view is all good then convert the image inside the view to a uiimage
     if #available(iOS 10.0, *) {

         let renderer = UIGraphicsImageRenderer(size: view!.bounds.size)
         let capturedImage = renderer.image { 
             (ctx) in
             view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: true)
         }
         return capturedImage

     } else {

         UIGraphicsBeginImageContextWithOptions((view!.bounds.size), view!.isOpaque, 0.0)
         view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: false)
         let capturedImage = UIGraphicsGetImageFromCurrentImageContext()
         UIGraphicsEndImageContext()
         return capturedImage!
     }
}

ต่อไปนี้เป็นวิธีดำเนินการกับรูปภาพที่ส่งคืนจากฟังก์ชัน:

@IBOutlet weak fileprivate var myCustomView: UIView!
var myPic: UIImage?

let myImageView = UIImageView()

@IBAction fileprivate func saveImageButtonTapped(_ sender: UIButton) {

   myPic = captureUIImageFromUIView(myCustomView)

   // display the pic inside a UIImageView
   myImageView.image = myPic!
}

ฉันได้รับคำตอบXcode 9 / Swift 3.2 / Swift 4จาก Paul Hudson แปลง uiview เป็น uiimage

ฉันได้รับXcode 8 / Swift 3จากที่ไหนสักแห่งเมื่อนานมาแล้วและฉันลืมไปแล้วว่า :(


ภาพจะแสดงและ / หรือบันทึกไว้ที่ใด
Famic Tech

@FamicTech เมื่อสร้างภาพแล้วเยาวชนจะตัดสินใจว่าจะทำอย่างไร ในตัวอย่างจากโค้ดของฉันฉันเพิ่งแปลง UIView เป็น UIImage ชื่อ "myPic" แต่ฉันไม่ได้ทำอะไรกับ 'myPic' ขั้นตอนต่อไปที่เป็นไปได้คือการแสดง 'myPic' ภายใน UIImageVIew ดังนี้ myImageVIew.image = myPic หากคุณใช้ collectionView และต้องการแสดงภาพในนั้นคุณจะสร้าง UIImageVIew ในแต่ละเซลล์จากนั้นแสดงภาพ (myPic) ภายใน UIImageVIew ผ่านทาง indexPath.item จากแหล่งข้อมูลเช่น myImageView.image = dataSource [indexPath .item] .myPic
Lance Samaria

@FamicTech คุณกำลังทำผิดพลาดเล็กน้อย สิ่งนี้ไม่เกี่ยวข้องกับคอลเลกชัน VIew คุณมีคลาส 2 ประเภท: UIImage และ UIView ทั้งสองแบบสามารถใช้เพื่อแสดงภาพใด ๆ ก็ได้ แต่ทั้งสองจะใช้วิธีที่แตกต่างกัน เกือบทุกอย่างใน iOS เป็นคลาสย่อยของ UIView แต่ UIImage สามารถแสดงภาพได้เท่านั้น (2 สิ่งที่แตกต่างกัน) สิ่งที่ฟังก์ชั่นนี้ใช้ UIVIew และแปลงเป็น UIImage ง่ายกว่าเช่น หากคุณต้องการแปลง 4.0 (a Double) เป็น 4 (Int) คุณจะส่งผลลัพธ์ Int (4.0) คือ 4 แต่ด้วยสิ่งนี้คุณจะแปลงรูปภาพใน UIVIew เป็น UIImage เข้าใจ?
Lance Samaria

สิ่งที่ฉันพยายามทำคือให้ผู้ใช้เข้ามาที่ Collection View Controller ของฉันและกดปุ่มที่ควรใช้มุมมองปัจจุบันซึ่งเป็นมุมมองคอลเลคชัน 10x10 และสร้างภาพของตาราง 10x10 ทั้งหมด (โปรดทราบว่าทั้งหมด ไม่สามารถมองเห็นเส้นตารางได้อย่างสมบูรณ์ในมุมมอง) โค้ดของคุณด้านบนแก้ปัญหาสำหรับกรณีการใช้งานนั้นหรือไม่
Famic Tech

ปุ่มนี้อยู่ในตัวควบคุมการนำทาง ผู้ใช้จะคลิกและ 'ควร' ใช้มุมมองคอลเลคชันที่แสดงภายใต้ตัวควบคุมการนำทางและสร้างรูปภาพของมุมมองคอลเลคชัน (PDF ก็ใช้ได้เช่นกัน) พร้อมข้อมูลทั้งหมดในเซลล์ในมุมมองคอลเลคชัน
Famic Tech

5
var snapshot = overView.snapshotViewAfterScreenUpdates(false)

หรือในวัตถุประสงค์ -c

UIView* snapshot = [overView snapshotViewAfterScreenUpdates:NO];

imageView เหมือนกับรูปภาพหรือไม่ ถ้าเป็นเช่นนั้นฉันจะบันทึกลงในแอพของฉันได้อย่างไร?
Sameer Hussain

4

คุณสามารถใช้งานได้อย่างง่ายดายโดยใช้ส่วนขยายเช่นนี้

// Take a snapshot from a view (just one view)
let viewSnapshot = myView.snapshot

// Take a screenshot (with every views in screen)
let screenSnapshot = UIApplication.shared.snapshot

// Take a snapshot from UIImage initialization
UIImage(view: self.view)

หากคุณต้องการใช้วิธี / ตัวแปรส่วนขยายเหล่านั้นให้ใช้สิ่งนี้

  1. ส่วนขยาย UIImage

    extension UIImage {
        convenience init(view: UIView) {
            if let cgImage = view.snapshot?.cgImage {
                self.init(cgImage: cgImage)
            } else {
                self.init()
            }
        }
    }
    
  2. ส่วนขยาย UIView

    extension UIView {
    
        var snapshot: UIImage? {
            UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0.0)
            if UIGraphicsGetCurrentContext() != nil {
                drawHierarchy(in: bounds, afterScreenUpdates: true)
                let screenshot = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                return screenshot
            }
            return nil
        }
    }
    
  3. UIA ส่วนขยายแอปพลิเคชัน

    extension UIApplication {
    
        var snapshot: UIImage? {
            return keyWindow?.rootViewController?.view.snapshot
        }
    }
    

ฉันมีมุมมองที่มีการปรับแต่ง zPositions มุมมองย่อยและคำตอบอื่น ๆ ไม่ได้ให้ตำแหน่งเลเยอร์ที่ถูกต้องขอบคุณ
Ashkan Ghodrat

3

หรือ iOS 10+ คุณสามารถใช้ UIGraphicsImageRenderer ใหม่ + drawHierarchy ที่แนะนำซึ่งในบางสถานการณ์อาจเร็วกว่า layer.renderInContext มาก

extension UIView {
    func asImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(size: self.bounds.size)
        return renderer.image { _ in
            self.drawHierarchy(in: CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height), afterScreenUpdates: false)
        }
    }
}

3

ขอบคุณ @Bao Tuan Diep! ฉันต้องการเพิ่มอาหารเสริม

เมื่อคุณใช้รหัส:

yourView.layer.render(in:UIGraphicsGetCurrentContext()!)

คุณต้องสังเกตว่า:

 - If you had used `autoLayout` or `Masonry` in `yourView` (that you want to convert) .
 - If you did not add `yourView` to another view which means that `yourView` was not used as a subview but just an object.

จากนั้นคุณต้องใช้ :

[yourView setNeedsLayout];
[yourView layoutIfNeeded];

การอัปเดตก่อนyourViewyourView.layer.render(in:UIGraphicsGetCurrentContext()!)

มิฉะนั้นคุณอาจได้รับวัตถุรูปภาพที่ไม่มีองค์ประกอบ


ขอบคุณสำหรับสิ่งนี้. ช่วยได้เยอะ !!
Maksim Kniazev

2

สวิฟต์ 4.2

import Foundation
import UIKit  

extension UIImage {

    convenience init(view: UIView) {

        UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
        view.drawHierarchy(in: view.bounds, afterScreenUpdates: false)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: (image?.cgImage)!)

    } 
}

ใช้:

ให้ img = UIImage.init (ดู: self.holderView)


1

การใช้งานในSwift 3 :

เพิ่มรหัสด้านล่างนอกขอบเขตชั้นเรียน

extension UIImage {
    convenience init(_ view: UIView) {
        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: (image?.cgImage)!)
    }
}

การใช้งาน:

let image = UIImage( Your_View_Outlet )

ได้รับข้อผิดพลาด "การวาดมุมมอง (0x1040a6970, UIView) ที่ไม่ได้แสดงผลอย่างน้อยหนึ่งครั้งต้องการ"
kishu mewara

0

ฉันใช้วิธีนี้ของ@Naveed J.และมันได้ผลอย่างมีเสน่ห์

นี่คือขอบเขตของเขา:

extension UIView {

    // Using a function since `var image` might conflict with an existing variable
    // (like on `UIImageView`)
    func asImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in
            layer.render(in: rendererContext.cgContext)
        }
    }
}

นี่คือวิธีที่ฉันใช้งาน

//create an image from yourView to display
//determine the frame of the view/imageimage
let screen = self.superview!.bounds
let width = screen.width / 4 //make image 1/4 width of screen
let height = width
let frame = CGRect(x: 0, y: 0, width: width, height: height)
let x = (screen.size.width - frame.size.width) * 0.5
let y = (screen.size.height - frame.size.height) * 0.5
let mainFrame = CGRect(x: x, y: y, width: frame.size.width, height: frame.size.height)

let yourView = YourView() //instantiate yourView
yourView.frame = mainFrame //give it the frame
yourView.setNeedsDisplay() //tell it to display (I am not 100% sure this is needed)

let characterViewImage = yourView.asImage()

0

Initializer พร้อม UIGraphicsImageRenderer ใหม่พร้อมใช้งานตั้งแต่ iOS 10:

extension UIImage{
    convenience init(view: UIView) {

    let renderer = UIGraphicsImageRenderer(size: self.bounds.size)
    let canvas = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height)
    let image = renderer.image { _ in
        self.drawHierarchy(in: canvas, afterScreenUpdates: false)
    }
    self.init(cgImage: (image?.cgImage)!)
  }
}

0

ทำงานได้ดีกับฉัน!

Swift4

 extension UIView {

    func toImage() -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0)
        self.drawHierarchy(in: self.bounds, afterScreenUpdates: false)
        let snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return snapshotImageFromMyView!
    }

    }

return snapshotImageFromMyView!หัวข้อที่ 1: ข้อผิดพลาดร้ายแรง: พบศูนย์โดยไม่คาดคิดขณะแกะค่าทางเลือก
Takasur

0

สำหรับมุมมองมีมุมมองย่อยที่เบลอ (เช่น อินสแตนซ์UIVisualEffectView ) ให้ใช้drawViewHierarchyInRect: afterScreenUpdates เท่านั้นเท่านั้น

คำตอบของ @ViJay Avhadถูกต้องสำหรับกรณีนี้


0

การใช้ UIGraphicsImageRenderer จะไม่ทำงานเมื่อมุมมองมีมุมมองย่อยของ Scene Kit, Metal หรือ Sprite Kit ในกรณีเหล่านี้ให้ใช้

let renderer = UIGraphicsImageRenderer(size: view.bounds.size)
let image = renderer.image { ctx in
    view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.