AirPrint contents of a UIView

2019-03-29 10:27发布

问题:

I'm trying to set up printing through an iPad app, where clicking Print will print a view with all of its contents. Here's what I've tried (pulled together from a few examples online):

// This is the View I want to print
// Just a 200x200 blue square
var testView = UIView(frame: CGRectMake(0, 0, 200, 200))
testView.backgroundColor = UIColor.blueColor()

let printInfo = UIPrintInfo(dictionary:nil)!
printInfo.outputType = UIPrintInfoOutputType.General
printInfo.jobName = "My Print Job"

// Set up print controller
let printController = UIPrintInteractionController.sharedPrintController()
printController!.printInfo = printInfo
// This is where I was thinking the print job got the
// contents to print to the page??
printController?.printFormatter = testView.viewPrintFormatter()

// Do it
printController!.presentFromRect(self.frame, inView: self, animated: true, completionHandler: nil)

However, I also read here that viewPrintFormatter is only available to UIWebView, UITextView, and MKMapView, is that correct?

When I print with this (using the printer simulator) I just get an empty page; tried with various printers/paper sizes.

Any guidance is much appreciated!

回答1:

I'm not sure if this is the proper way to do it, but I ended up solving this by converting the view to a UIImage and then setting it as the print controller's printingItem.

Updated code:

// This is the View I want to print
// Just a 200x200 blue square
var testView = UIView(frame: CGRectMake(0, 0, 200, 200))
testView.backgroundColor = UIColor.blueColor()

let printInfo = UIPrintInfo(dictionary:nil)!
printInfo.outputType = UIPrintInfoOutputType.General
printInfo.jobName = "My Print Job"

// Set up print controller
let printController = UIPrintInteractionController.sharedPrintController()
printController!.printInfo = printInfo

// Assign a UIImage version of my UIView as a printing iten
printController?.printingItem = testView!.toImage()

// Do it
printController!.presentFromRect(self.frame, inView: self, animated: true, completionHandler: nil)

The toImage() method is an extension to UIView:

extension UIView {
    func toImage() -> UIImage {
        UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.mainScreen().scale)

        drawViewHierarchyInRect(self.bounds, afterScreenUpdates: true)

        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

Open to alternative approaches if anyone has one!



回答2:

Maybe someone (like me) needs to add border to the imageview before send it to the printer (otherwise the image will automatically fits to the sheet). I searched for some build-in methods in order to do this, but I haven't found it (btw, I read some hints from here). The trick is to add the view containing the image to an external view, and then center it.

    let borderWidth: CGFloat = 100.0
    let myImage = UIImage(named: "myImage.jpg")
    let internalPrintView = UIImageView(frame: CGRectMake(0, 0, myImage.size.width, myImage.size.height))
    let printView = UIView(frame: CGRectMake(0, 0, myImage.size.width + borderWidth*2, myImage.size.height + borderWidth*2))
    internalPrintView.image = myImage
    internalPrintView.center = CGPointMake(printView.frame.size.width/2, printView.frame.size.height/2)
    printView.addSubview(internalPrintView)
    printController.printingItem = printView.toImage()

It's a little bit complex but it does its dirty job.