swiftUI之macOS 打印功能解决文本被截断的问题

swiftUI之macOS 打印功能解决文本被截断的问题

概述

在之前的文章中介绍了macOS中如何调用打印功能,用那种方式如果只打印一页的内容,则无妨,如果是多页,则会出现文本前后被截断的问题如下图的效果:
文字被截断的效果
出现这样的问题,最大的原因就是打印view的时候没有处理分页,而是让系统自动分页,导致一个view绘制下来边界会被截断,所以,解决的这个问题的关键在于,如何在每一页只绘制一页所能展示的内容,数据上要做切割,然后还有一点是如何将切割好的数据,转移到对应的页面上去,关于这个问题我研究了好几天,找遍了stackoverflow也没有找到对应的解决方案,都是比较模糊的指向自定义view,去实现分页,我也尝试了,并没有成功,可能是我的做法有问题吧,虽然能分页但是绘制的内容有问题,后面我自己又另辟蹊径找到了别的替代方法。

解决方案

这个问题的解决方案还是的归功于PDFKit,之前我知道这个库是专门处理PDF的,但是不知道如何将编辑框的内容加载到里面去,后面我发现他的API中有能将view转化为data的方法:

        var data = view.dataWithPDF(inside: NSMakeRect(0, 0, contentWidth, onePageHeight))

既然能转为PDF data数据,那就好办了。直接创PDFDocument。

    let pdfDocument = PDFDocument(data: data)!

能创建PDFDocument,就能通过对应的API调起打印功能:

        let print = pdfDocument.printOperation(for: printInfo, scalingMode: .pageScaleNone, autoRotate: true)
        print?.showsPrintPanel = true
        print?.showsProgressPanel = true
        print?.run()

这和创建NSPrintOperation一样,是这个框架自带的打印功能,如果你只是想生存PDF文件,直接调用write方法就行了。不得不说在Mac上,只要你找对了方法实现起来还是很简单的,主要是资料太少了,做的人也不多,一些方法鲜有人知。
我这边项目的需求是将大的文本编辑框中的内容打印或者输出位PDF,如果有相同需求的,可以照搬代码,首先拿到编辑框的内容:

		//我这边还需要在最开始的位置添加一些内容
        let headerStr = self.addHeaderInfo()
        //为了让编辑框内容不受添加头信息的影响,editBoxContent的内容是双向绑定的,更改了也会影响编辑框里面的内容变化。
        var readyPrintContent: String = editBoxContent
        let index = readyPrintContent.startIndex
        //插入到开始位置。
        readyPrintContent.insert(contentsOf: headerStr, at: index)

然后将单行内容切割出来,后面要根据每行的高度计算一页的高度,对整体内容进行分页切割。

 var printContent: String = ""
        let compt = readyPrintContent.components(separatedBy: "\n")
        let contentWidth = printInfo.paperSize.width - printInfo.leftMargin - printInfo.rightMargin
        let onePageHeight = printInfo.paperSize.height - printInfo.topMargin - printInfo.bottomMargin
        var currentPageHeight:CGFloat = 0
        //以空一行作为页的切割标志
        for i in compt.indices {
        //计算文本高度的方法,前面的文章有提到过
            let textHeight = compt[i].getheightForComment(fontSize: 12, width: contentWidth)
            currentPageHeight = currentPageHeight + textHeight
            if currentPageHeight >= onePageHeight - 30 {
                currentPageHeight = 0
                printContent.append("\n")
            }
            printContent.append(compt[i]+"\n")
            
        }

然后切割页:

let splitPages = printContent.components(separatedBy: "\n\n")

这样处理之后,页的数据就已经切割好了,然后关键的步骤将页的数据,添加到每一页。
先取第一页的内容,创建PDFDocument:

		//PrintView是自己定义的展示内容的view,起始里面就包了个Text。通过NSHostingView转换一下。
        let view = NSHostingView(rootView: PrintView(text: splitPages[0]))
        //必须要设置frame的size
        view.frame.size = CGSize(width: contentWidth, height: onePageHeight)
        //转换为PDF data
        var data = view.dataWithPDF(inside: NSMakeRect(0, 0, contentWidth, onePageHeight))
        //创建pdfDocument
        let pdfDocument = PDFDocument(data: data)!

下面是关键步骤,将内容添加到每一页PDF上:

		//前面已经绘制了一页了,要从第二页开始。
		if splitPages.count > 1 {
         for page in 1 ..< splitPages.count - 1{
            let view = NSHostingView(rootView: PrintView(text: splitPages[page]))
            view.frame.size = CGSize(width: contentWidth, height: onePageHeight)
            data = view.dataWithPDF(inside: NSMakeRect(0, 0, contentWidth, onePageHeight))
            let pdfPage = PDFPage(image: NSImage(data: data)!)!
            pdfDocument.insert(pdfPage, at: pdfDocument.pageCount)
         }
       }

最后调起打印功能,则大功告成,是不是很简单。

        let print = pdfDocument.printOperation(for: printInfo, scalingMode: .pageScaleNone, autoRotate: true)
        print?.showsPrintPanel = true
        print?.showsProgressPanel = true
        print?.run()

发现了方法,做起来就很简单了,可以说找方法用了很长时间,解决问题之用了几分钟,留下解决方案也是希望有同样需求的开发者能少走弯路,我们都在寻着别人的脚步,别人的经验,快速的解决我们遇到的问题,如果我的方案解决了你的问题,别忘了点个赞哦。有问题可以私信我。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值