Swift 5 - 如何使用 PDFKit 在 PDF 中创建 table
Swift 5 - How to create table in PDF with PDFKit
我在 UIGraphicsPDFRendererFormat 中有高度为 400 的信息,我想在其中附加一个 table,但如果 table 大于页面,我需要自动创建新页面并继续其他页面中的table。
我找到了有关将 UITableView 转换为 PDF 的答案,但我没有使用 UITableView。
我要用数组填充 table:names:[String] , addresses:[String], money:[Double]
Array Money 应该在 table.
结束时自动求和
那么如果内容比较大,如何绘制并自动创建新页面呢?
要计算每页的项目数,您可以使用公式:
pageRectangle.height / rowHeight
从而找出每页的元素数。
您也可以选择减去顶部和底部缩进。
它应该看起来像下一个:
您可以在下面找到示例项目,它详细回答了您的问题(将其放入已创建项目的 ViewController)
import UIKit
import PDFKit
// Mock data
let names = ["Jenice Littler", "Marianna Harned", "Rosendo Laubach", "Lawrence Ritchie", "Dolores Mcnelly", "Jarred Edens", "Lakia Harten", "Jannette Duer", "Johnny Stinger", "Olympia Mclane", "Manda Kersh", "Clint Muller", "Anjanette Simkins", "Genny Mayhew", "Bonny Risser", "Bridgette Groth", "Glenda Mirarchi", "Omar Ashbrook", "Deedee Luker", "Caitlyn Borgeson", "Arden Maloy", "Orval Esper", "Carole Wendland", "Tiffanie Popp", "Whitley Davie", "Janett Carrara", "Rosia Stalvey", "Taunya Pinkney", "Bertram Hemmingway", "Dalia Hulett", "Alejandrina Heinz", "Marlena Goold", "Randa Cornish", "Nicolette Drexler", "Christi Collinson", "Harris Pesina", "Natasha Sommers", "Terrance Jarboe", "Avery Prouty", "Louise Shire", "Corrie Kapinos", "Bao Milstead", "Tran Mcpeak", "Cody Dewald", "Paris Newkirk", "Felisha Verona", "Milo Eno", "Nicole Bryand", "Anya Wierenga", "Dinah Levitsky"]
let addresses = ["667 Gates St. Paterson, NJ 07501", "6 Riverside Court Ellicott City, MD 21042", "282 Philmont Street Howell, NJ 07731", "120 N. Lake View Drive Wheaton, IL 60187", "748 S. Riverview St. Chapel Hill, NC 27516", "7038 Bridle Road Pottstown, PA 19464", "84 South Peninsula Dr. Merrick, NY 11566", "65 Blackburn Drive West Islip, NY 11795", "3 Whitemarsh Street Piscataway, NJ 08854", "8559 Mayfield Lane Taylor, MI 48180", "51 St Margarets Dr. Phoenixville, PA 19460", "224 East Bridgeton Circle Billings, MT 59101", "7 Arlington Drive Boca Raton, FL 33428", "74 Jennings St. Irwin, PA 15642", "9257 Mill Pond Street Painesville, OH 44077", "447 Rockaway Ave. Des Plaines, IL 60016", "34 Princess St. Waldorf, MD 20601", "8486 West Glen Creek Ave. Amsterdam, NY 12010", "748 Summer Rd. Los Angeles, CA 90008", "31 Victoria Lane Latrobe, PA 15650", "838 Central Ave. Utica, NY 13501", "123 Vine Rd. Lawndale, CA 90260", "632 Del Monte Dr. Williamstown, NJ 08094", "8626 Country Drive Williamsport, PA 17701", "4 Vermont St. Elizabethtown, PA 17022", "7752 Laurel Lane Ambler, PA 19002", "828 Creek Dr. Biloxi, MS 39532", "7950 South Pennsylvania Ave. Hollywood, FL 33020", "7645 Tunnel Ave. Culpeper, VA 22701", "199 Hudson St. Kaukauna, WI 54130", "689 Berkshire St. Apple Valley, CA 92307", "97A Lyme Ave. Janesville, WI 53546", "134 Cedarwood St. Middleton, WI 53562", "738 Coffee Street Elizabethton, TN 37643", "569 College Drive Buffalo, NY 14215", "87 Front Street State College, PA 16801", "8069 Kirkland Drive Portage, IN 46368", "48 Eagle Ave. Elmont, NY 11003", "833 Virginia Ave. Encino, CA 91316", "662 Boston Court Staten Island, NY 10301", "7233 Devonshire Court New Brunswick, NJ 08901", "65 Virginia Drive Seattle, WA 98144", "388 Sierra St. Middleburg, FL 32068", "641 SW. Gulf St. Waterbury, CT 06705", "8279 Mill Pond St. Staunton, VA 24401", "56 Deerfield St. Cranberry Twp, PA 16066", "9289 Hilldale Ave. Lakeland, FL 33801", "7486 Poplar St. Brainerd, MN 56401", "2 Berkshire Road Missoula, MT 59801", "160 Kirkland Ave. Clifton Park, NY 12065"]
let money = [55.08, 87.75, 72.00, 96.79, 17.07, 85.36, 75.44, 70.35, 28.39, 46.17, 84.70, 37.47, 23.22, 97.98, 56.23, 47.89, 40.56, 86.50, 30.93, 50.15, 22.19, 95.70, 26.48, 79.48, 15.27, 15.00, 45.36, 88.26, 11.49, 48.96, 58.58, 56.04, 95.31, 21.56, 63.44, 90.83, 22.12, 88.17, 19.75, 30.65, 47.00, 39.82, 26.83, 91.12, 54.61, 35.06, 16.54, 78.64, 90.66, 41.81]
struct TableDataItem {
let name: String
let address: String
let money: Double
init(name: String, address: String, money: Double) {
self.name = name
self.address = address
self.money = money
}
}
class ViewController: UIViewController {
var pdfView: PDFView!
override func viewDidLoad() {
super.viewDidLoad()
createUI()
createPDF()
}
func createUI() {
pdfView = PDFView()
pdfView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(pdfView)
pdfView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
pdfView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
pdfView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
pdfView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
}
func createPDF() {
var tableDataItems = [TableDataItem]()
for itemIndex in 0..<names.count {
tableDataItems.append(TableDataItem(name: names[itemIndex], address: addresses[itemIndex], money: money[itemIndex]))
}
let sumItem = money.reduce(0, +)
tableDataItems.append(TableDataItem(name: "", address: "sum:", money: sumItem))
let tableDataHeaderTitles = ["name", "address", "money"]
let pdfCreator = PDFCreator(tableDataItems: tableDataItems, tableDataHeaderTitles: tableDataHeaderTitles)
let data = pdfCreator.create()
pdfView.document = PDFDocument(data: data)
pdfView.autoScales = true
}
}
// inspired by Paul Hudson
extension Array {
func chunkedElements(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[[=10=] ..< Swift.min([=10=] + size, count)])
}
}
}
class PDFCreator: NSObject {
let defaultOffset: CGFloat = 20
let tableDataHeaderTitles: [String]
let tableDataItems: [TableDataItem]
init(tableDataItems: [TableDataItem], tableDataHeaderTitles: [String]) {
self.tableDataItems = tableDataItems
self.tableDataHeaderTitles = tableDataHeaderTitles
}
func create() -> Data {
// default page format
let pageWidth = 8.5 * 72.0
let pageHeight = 11 * 72.0
let pageRect = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight)
let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: UIGraphicsPDFRendererFormat())
let numberOfElementsPerPage = calculateNumberOfElementsPerPage(with: pageRect)
let tableDataChunked: [[TableDataItem]] = tableDataItems.chunkedElements(into: numberOfElementsPerPage)
let data = renderer.pdfData { context in
for tableDataChunk in tableDataChunked {
context.beginPage()
let cgContext = context.cgContext
drawTableHeaderRect(drawContext: cgContext, pageRect: pageRect)
drawTableHeaderTitles(titles: tableDataHeaderTitles, drawContext: cgContext, pageRect: pageRect)
drawTableContentInnerBordersAndText(drawContext: cgContext, pageRect: pageRect, tableDataItems: tableDataChunk)
}
}
return data
}
func calculateNumberOfElementsPerPage(with pageRect: CGRect) -> Int {
let rowHeight = (defaultOffset * 3)
let number = Int((pageRect.height - rowHeight) / rowHeight)
return number
}
}
// Drawings
extension PDFCreator {
func drawTableHeaderRect(drawContext: CGContext, pageRect: CGRect) {
drawContext.saveGState()
drawContext.setLineWidth(3.0)
// Draw header's 1 top horizontal line
drawContext.move(to: CGPoint(x: defaultOffset, y: defaultOffset))
drawContext.addLine(to: CGPoint(x: pageRect.width - defaultOffset, y: defaultOffset))
drawContext.strokePath()
// Draw header's 1 bottom horizontal line
drawContext.move(to: CGPoint(x: defaultOffset, y: defaultOffset * 3))
drawContext.addLine(to: CGPoint(x: pageRect.width - defaultOffset, y: defaultOffset * 3))
drawContext.strokePath()
// Draw header's 3 vertical lines
drawContext.setLineWidth(2.0)
drawContext.saveGState()
let tabWidth = (pageRect.width - defaultOffset * 2) / CGFloat(3)
for verticalLineIndex in 0..<4 {
let tabX = CGFloat(verticalLineIndex) * tabWidth
drawContext.move(to: CGPoint(x: tabX + defaultOffset, y: defaultOffset))
drawContext.addLine(to: CGPoint(x: tabX + defaultOffset, y: defaultOffset * 3))
drawContext.strokePath()
}
drawContext.restoreGState()
}
func drawTableHeaderTitles(titles: [String], drawContext: CGContext, pageRect: CGRect) {
// prepare title attributes
let textFont = UIFont.systemFont(ofSize: 16.0, weight: .medium)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
paragraphStyle.lineBreakMode = .byWordWrapping
let titleAttributes = [
NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.font: textFont
]
// draw titles
let tabWidth = (pageRect.width - defaultOffset * 2) / CGFloat(3)
for titleIndex in 0..<titles.count {
let attributedTitle = NSAttributedString(string: titles[titleIndex].capitalized, attributes: titleAttributes)
let tabX = CGFloat(titleIndex) * tabWidth
let textRect = CGRect(x: tabX + defaultOffset,
y: defaultOffset * 3 / 2,
width: tabWidth,
height: defaultOffset * 2)
attributedTitle.draw(in: textRect)
}
}
func drawTableContentInnerBordersAndText(drawContext: CGContext, pageRect: CGRect, tableDataItems: [TableDataItem]) {
drawContext.setLineWidth(1.0)
drawContext.saveGState()
let defaultStartY = defaultOffset * 3
for elementIndex in 0..<tableDataItems.count {
let yPosition = CGFloat(elementIndex) * defaultStartY + defaultStartY
// Draw content's elements texts
let textFont = UIFont.systemFont(ofSize: 13.0, weight: .regular)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
paragraphStyle.lineBreakMode = .byWordWrapping
let textAttributes = [
NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.font: textFont
]
let tabWidth = (pageRect.width - defaultOffset * 2) / CGFloat(3)
for titleIndex in 0..<3 {
var attributedText = NSAttributedString(string: "", attributes: textAttributes)
switch titleIndex {
case 0: attributedText = NSAttributedString(string: tableDataItems[elementIndex].name, attributes: textAttributes)
case 1: attributedText = NSAttributedString(string: tableDataItems[elementIndex].address, attributes: textAttributes)
case 2: attributedText = NSAttributedString(string: String(format: "%.2f", tableDataItems[elementIndex].money), attributes: textAttributes)
default:
break
}
let tabX = CGFloat(titleIndex) * tabWidth
let textRect = CGRect(x: tabX + defaultOffset,
y: yPosition + defaultOffset,
width: tabWidth,
height: defaultOffset * 3)
attributedText.draw(in: textRect)
}
// Draw content's 3 vertical lines
for verticalLineIndex in 0..<4 {
let tabX = CGFloat(verticalLineIndex) * tabWidth
drawContext.move(to: CGPoint(x: tabX + defaultOffset, y: yPosition))
drawContext.addLine(to: CGPoint(x: tabX + defaultOffset, y: yPosition + defaultStartY))
drawContext.strokePath()
}
// Draw content's element bottom horizontal line
drawContext.move(to: CGPoint(x: defaultOffset, y: yPosition + defaultStartY))
drawContext.addLine(to: CGPoint(x: pageRect.width - defaultOffset, y: yPosition + defaultStartY))
drawContext.strokePath()
}
drawContext.restoreGState()
}
}
使用的材料:
- 项目灵感来自 RayWenderlich.com tutorial
- 随机名称:http://listofrandomnames.com
- 随机地址:https://www.randomlists.com
- 随机货币:
Float.random(in: 9...99)
我在 UIGraphicsPDFRendererFormat 中有高度为 400 的信息,我想在其中附加一个 table,但如果 table 大于页面,我需要自动创建新页面并继续其他页面中的table。
我找到了有关将 UITableView 转换为 PDF 的答案,但我没有使用 UITableView。
我要用数组填充 table:names:[String] , addresses:[String], money:[Double]
Array Money 应该在 table.
那么如果内容比较大,如何绘制并自动创建新页面呢?
要计算每页的项目数,您可以使用公式:
pageRectangle.height / rowHeight
从而找出每页的元素数。 您也可以选择减去顶部和底部缩进。 它应该看起来像下一个:
您可以在下面找到示例项目,它详细回答了您的问题(将其放入已创建项目的 ViewController)
import UIKit
import PDFKit
// Mock data
let names = ["Jenice Littler", "Marianna Harned", "Rosendo Laubach", "Lawrence Ritchie", "Dolores Mcnelly", "Jarred Edens", "Lakia Harten", "Jannette Duer", "Johnny Stinger", "Olympia Mclane", "Manda Kersh", "Clint Muller", "Anjanette Simkins", "Genny Mayhew", "Bonny Risser", "Bridgette Groth", "Glenda Mirarchi", "Omar Ashbrook", "Deedee Luker", "Caitlyn Borgeson", "Arden Maloy", "Orval Esper", "Carole Wendland", "Tiffanie Popp", "Whitley Davie", "Janett Carrara", "Rosia Stalvey", "Taunya Pinkney", "Bertram Hemmingway", "Dalia Hulett", "Alejandrina Heinz", "Marlena Goold", "Randa Cornish", "Nicolette Drexler", "Christi Collinson", "Harris Pesina", "Natasha Sommers", "Terrance Jarboe", "Avery Prouty", "Louise Shire", "Corrie Kapinos", "Bao Milstead", "Tran Mcpeak", "Cody Dewald", "Paris Newkirk", "Felisha Verona", "Milo Eno", "Nicole Bryand", "Anya Wierenga", "Dinah Levitsky"]
let addresses = ["667 Gates St. Paterson, NJ 07501", "6 Riverside Court Ellicott City, MD 21042", "282 Philmont Street Howell, NJ 07731", "120 N. Lake View Drive Wheaton, IL 60187", "748 S. Riverview St. Chapel Hill, NC 27516", "7038 Bridle Road Pottstown, PA 19464", "84 South Peninsula Dr. Merrick, NY 11566", "65 Blackburn Drive West Islip, NY 11795", "3 Whitemarsh Street Piscataway, NJ 08854", "8559 Mayfield Lane Taylor, MI 48180", "51 St Margarets Dr. Phoenixville, PA 19460", "224 East Bridgeton Circle Billings, MT 59101", "7 Arlington Drive Boca Raton, FL 33428", "74 Jennings St. Irwin, PA 15642", "9257 Mill Pond Street Painesville, OH 44077", "447 Rockaway Ave. Des Plaines, IL 60016", "34 Princess St. Waldorf, MD 20601", "8486 West Glen Creek Ave. Amsterdam, NY 12010", "748 Summer Rd. Los Angeles, CA 90008", "31 Victoria Lane Latrobe, PA 15650", "838 Central Ave. Utica, NY 13501", "123 Vine Rd. Lawndale, CA 90260", "632 Del Monte Dr. Williamstown, NJ 08094", "8626 Country Drive Williamsport, PA 17701", "4 Vermont St. Elizabethtown, PA 17022", "7752 Laurel Lane Ambler, PA 19002", "828 Creek Dr. Biloxi, MS 39532", "7950 South Pennsylvania Ave. Hollywood, FL 33020", "7645 Tunnel Ave. Culpeper, VA 22701", "199 Hudson St. Kaukauna, WI 54130", "689 Berkshire St. Apple Valley, CA 92307", "97A Lyme Ave. Janesville, WI 53546", "134 Cedarwood St. Middleton, WI 53562", "738 Coffee Street Elizabethton, TN 37643", "569 College Drive Buffalo, NY 14215", "87 Front Street State College, PA 16801", "8069 Kirkland Drive Portage, IN 46368", "48 Eagle Ave. Elmont, NY 11003", "833 Virginia Ave. Encino, CA 91316", "662 Boston Court Staten Island, NY 10301", "7233 Devonshire Court New Brunswick, NJ 08901", "65 Virginia Drive Seattle, WA 98144", "388 Sierra St. Middleburg, FL 32068", "641 SW. Gulf St. Waterbury, CT 06705", "8279 Mill Pond St. Staunton, VA 24401", "56 Deerfield St. Cranberry Twp, PA 16066", "9289 Hilldale Ave. Lakeland, FL 33801", "7486 Poplar St. Brainerd, MN 56401", "2 Berkshire Road Missoula, MT 59801", "160 Kirkland Ave. Clifton Park, NY 12065"]
let money = [55.08, 87.75, 72.00, 96.79, 17.07, 85.36, 75.44, 70.35, 28.39, 46.17, 84.70, 37.47, 23.22, 97.98, 56.23, 47.89, 40.56, 86.50, 30.93, 50.15, 22.19, 95.70, 26.48, 79.48, 15.27, 15.00, 45.36, 88.26, 11.49, 48.96, 58.58, 56.04, 95.31, 21.56, 63.44, 90.83, 22.12, 88.17, 19.75, 30.65, 47.00, 39.82, 26.83, 91.12, 54.61, 35.06, 16.54, 78.64, 90.66, 41.81]
struct TableDataItem {
let name: String
let address: String
let money: Double
init(name: String, address: String, money: Double) {
self.name = name
self.address = address
self.money = money
}
}
class ViewController: UIViewController {
var pdfView: PDFView!
override func viewDidLoad() {
super.viewDidLoad()
createUI()
createPDF()
}
func createUI() {
pdfView = PDFView()
pdfView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(pdfView)
pdfView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
pdfView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
pdfView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
pdfView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
}
func createPDF() {
var tableDataItems = [TableDataItem]()
for itemIndex in 0..<names.count {
tableDataItems.append(TableDataItem(name: names[itemIndex], address: addresses[itemIndex], money: money[itemIndex]))
}
let sumItem = money.reduce(0, +)
tableDataItems.append(TableDataItem(name: "", address: "sum:", money: sumItem))
let tableDataHeaderTitles = ["name", "address", "money"]
let pdfCreator = PDFCreator(tableDataItems: tableDataItems, tableDataHeaderTitles: tableDataHeaderTitles)
let data = pdfCreator.create()
pdfView.document = PDFDocument(data: data)
pdfView.autoScales = true
}
}
// inspired by Paul Hudson
extension Array {
func chunkedElements(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[[=10=] ..< Swift.min([=10=] + size, count)])
}
}
}
class PDFCreator: NSObject {
let defaultOffset: CGFloat = 20
let tableDataHeaderTitles: [String]
let tableDataItems: [TableDataItem]
init(tableDataItems: [TableDataItem], tableDataHeaderTitles: [String]) {
self.tableDataItems = tableDataItems
self.tableDataHeaderTitles = tableDataHeaderTitles
}
func create() -> Data {
// default page format
let pageWidth = 8.5 * 72.0
let pageHeight = 11 * 72.0
let pageRect = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight)
let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: UIGraphicsPDFRendererFormat())
let numberOfElementsPerPage = calculateNumberOfElementsPerPage(with: pageRect)
let tableDataChunked: [[TableDataItem]] = tableDataItems.chunkedElements(into: numberOfElementsPerPage)
let data = renderer.pdfData { context in
for tableDataChunk in tableDataChunked {
context.beginPage()
let cgContext = context.cgContext
drawTableHeaderRect(drawContext: cgContext, pageRect: pageRect)
drawTableHeaderTitles(titles: tableDataHeaderTitles, drawContext: cgContext, pageRect: pageRect)
drawTableContentInnerBordersAndText(drawContext: cgContext, pageRect: pageRect, tableDataItems: tableDataChunk)
}
}
return data
}
func calculateNumberOfElementsPerPage(with pageRect: CGRect) -> Int {
let rowHeight = (defaultOffset * 3)
let number = Int((pageRect.height - rowHeight) / rowHeight)
return number
}
}
// Drawings
extension PDFCreator {
func drawTableHeaderRect(drawContext: CGContext, pageRect: CGRect) {
drawContext.saveGState()
drawContext.setLineWidth(3.0)
// Draw header's 1 top horizontal line
drawContext.move(to: CGPoint(x: defaultOffset, y: defaultOffset))
drawContext.addLine(to: CGPoint(x: pageRect.width - defaultOffset, y: defaultOffset))
drawContext.strokePath()
// Draw header's 1 bottom horizontal line
drawContext.move(to: CGPoint(x: defaultOffset, y: defaultOffset * 3))
drawContext.addLine(to: CGPoint(x: pageRect.width - defaultOffset, y: defaultOffset * 3))
drawContext.strokePath()
// Draw header's 3 vertical lines
drawContext.setLineWidth(2.0)
drawContext.saveGState()
let tabWidth = (pageRect.width - defaultOffset * 2) / CGFloat(3)
for verticalLineIndex in 0..<4 {
let tabX = CGFloat(verticalLineIndex) * tabWidth
drawContext.move(to: CGPoint(x: tabX + defaultOffset, y: defaultOffset))
drawContext.addLine(to: CGPoint(x: tabX + defaultOffset, y: defaultOffset * 3))
drawContext.strokePath()
}
drawContext.restoreGState()
}
func drawTableHeaderTitles(titles: [String], drawContext: CGContext, pageRect: CGRect) {
// prepare title attributes
let textFont = UIFont.systemFont(ofSize: 16.0, weight: .medium)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
paragraphStyle.lineBreakMode = .byWordWrapping
let titleAttributes = [
NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.font: textFont
]
// draw titles
let tabWidth = (pageRect.width - defaultOffset * 2) / CGFloat(3)
for titleIndex in 0..<titles.count {
let attributedTitle = NSAttributedString(string: titles[titleIndex].capitalized, attributes: titleAttributes)
let tabX = CGFloat(titleIndex) * tabWidth
let textRect = CGRect(x: tabX + defaultOffset,
y: defaultOffset * 3 / 2,
width: tabWidth,
height: defaultOffset * 2)
attributedTitle.draw(in: textRect)
}
}
func drawTableContentInnerBordersAndText(drawContext: CGContext, pageRect: CGRect, tableDataItems: [TableDataItem]) {
drawContext.setLineWidth(1.0)
drawContext.saveGState()
let defaultStartY = defaultOffset * 3
for elementIndex in 0..<tableDataItems.count {
let yPosition = CGFloat(elementIndex) * defaultStartY + defaultStartY
// Draw content's elements texts
let textFont = UIFont.systemFont(ofSize: 13.0, weight: .regular)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
paragraphStyle.lineBreakMode = .byWordWrapping
let textAttributes = [
NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.font: textFont
]
let tabWidth = (pageRect.width - defaultOffset * 2) / CGFloat(3)
for titleIndex in 0..<3 {
var attributedText = NSAttributedString(string: "", attributes: textAttributes)
switch titleIndex {
case 0: attributedText = NSAttributedString(string: tableDataItems[elementIndex].name, attributes: textAttributes)
case 1: attributedText = NSAttributedString(string: tableDataItems[elementIndex].address, attributes: textAttributes)
case 2: attributedText = NSAttributedString(string: String(format: "%.2f", tableDataItems[elementIndex].money), attributes: textAttributes)
default:
break
}
let tabX = CGFloat(titleIndex) * tabWidth
let textRect = CGRect(x: tabX + defaultOffset,
y: yPosition + defaultOffset,
width: tabWidth,
height: defaultOffset * 3)
attributedText.draw(in: textRect)
}
// Draw content's 3 vertical lines
for verticalLineIndex in 0..<4 {
let tabX = CGFloat(verticalLineIndex) * tabWidth
drawContext.move(to: CGPoint(x: tabX + defaultOffset, y: yPosition))
drawContext.addLine(to: CGPoint(x: tabX + defaultOffset, y: yPosition + defaultStartY))
drawContext.strokePath()
}
// Draw content's element bottom horizontal line
drawContext.move(to: CGPoint(x: defaultOffset, y: yPosition + defaultStartY))
drawContext.addLine(to: CGPoint(x: pageRect.width - defaultOffset, y: yPosition + defaultStartY))
drawContext.strokePath()
}
drawContext.restoreGState()
}
}
使用的材料:
- 项目灵感来自 RayWenderlich.com tutorial
- 随机名称:http://listofrandomnames.com
- 随机地址:https://www.randomlists.com
- 随机货币:
Float.random(in: 9...99)