我创建了一个示例项目,用于使用 itextpdf/itext7 库
从数据中创建 pdf 文件
示例项目链接:https://github.com/rheyansh/RPdfGenerator
在您的应用程序 gradle 中添加以下依赖项:
implementation 'com.itextpdf:itext7-core:7.1.12'
重要提示
在 AndroidManifest.xml 中添加 WRITE_EXTERNAL_STORAGE 权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
在 AndroidManifest.xml 中添加文件提供程序
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.rheyansh.rpdfgenerator.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
添加 XML 资源文件夹(参见示例文件夹中的 provider_paths.xml)
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>
创建 RPdfGenerator 类
import android.content.Context
import android.os.Environment
import com.rheyansh.model.RTransaction
import android.widget.Toast
import com.itextpdf.io.font.constants.StandardFonts
import com.itextpdf.kernel.colors.ColorConstants
import com.itextpdf.kernel.font.PdfFontFactory
import com.itextpdf.kernel.pdf.PdfDocument
import com.itextpdf.kernel.pdf.PdfWriter
import com.itextpdf.kernel.pdf.action.PdfAction
import com.itextpdf.layout.Document
import com.itextpdf.layout.element.Paragraph
import com.itextpdf.layout.element.Table
import com.itextpdf.layout.element.Text
import com.itextpdf.layout.property.TextAlignment
import com.itextpdf.layout.property.UnitValue
import com.rheyansh.lenden.model.RPdfGeneratorModel
import java.io.File
import java.io.FileOutputStream
object RPdfGenerator {
private val linkSample = "https://github.com/rheyansh/RPdfGenerator"
fun generatePdf(context: Context, info: RPdfGeneratorModel) {
val FILENAME = info.header + ".pdf"
val filePath = getAppPath(context) + FILENAME
if (File(filePath).exists()) {
File(filePath).delete()
}
val fOut = FileOutputStream(filePath)
val pdfWriter = PdfWriter(fOut)
// Creating a PdfDocument
val pdfDocument =
PdfDocument(pdfWriter)
val layoutDocument = Document(pdfDocument)
// title
addTitle(layoutDocument, info.header)
//add empty line
addEmptyLine(layoutDocument,1)
//Add sub heading
val appName = "RPdfGenerator"
addSubHeading(layoutDocument, "Generated via: ${appName}")
addLink(layoutDocument, linkSample)
//add empty line
addEmptyLine(layoutDocument,1)
// customer reference information
addDebitCredit(layoutDocument, info)
//add empty line
addEmptyLine(layoutDocument,1)
//Add sub heading
addSubHeading(layoutDocument, "Transactions")
//Add list
addTable(layoutDocument, info.list)
layoutDocument.close()
Toast.makeText(context, "Pdf saved successfully to location $filePath", Toast.LENGTH_LONG).show()
//FileUtils.openFile(context, File(filePath))
}
private fun getAppPath(context: Context): String {
val dir = File(
Environment.getExternalStorageDirectory()
.toString() + File.separator
+ context.resources.getString(R.string.app_name)
+ File.separator
)
if (!dir.exists()) {
dir.mkdir()
}
return dir.path + File.separator
}
private fun addTable(layoutDocument: Document, items: List<RTransaction>) {
val table = Table(
UnitValue.createPointArray(
floatArrayOf(
100f,
180f,
80f,
80f,
80f,
100f
)
)
)
// headers
//table.addCell(Paragraph("S.N.O.").setBold())
table.addCell(Paragraph("Item").setBold())
table.addCell(Paragraph("Customer").setBold())
table.addCell(Paragraph("Qty").setBold())
table.addCell(Paragraph("Price/Q").setBold())
table.addCell(Paragraph("Total").setBold())
table.addCell(Paragraph("Date").setBold())
// items
for (a in items) {
// table.addCell(Paragraph(a.SNO.toString() + ""))
table.addCell(Paragraph(a.itemName + ""))
table.addCell(Paragraph(a.custName + ""))
table.addCell(Paragraph(a.quantity.toString() + ""))
table.addCell(Paragraph(a.pricePerUnit.toString() + ""))
table.addCell(Paragraph((a.quantity * a.pricePerUnit).toString() + ""))
table.addCell(Paragraph(a.transactionDateStr + ""))
}
layoutDocument.add(table)
}
private fun addEmptyLine(layoutDocument: Document, number: Int) {
for (i in 0 until number) {
layoutDocument.add(Paragraph(" "))
}
}
private fun addDebitCredit(layoutDocument: Document, info: RPdfGeneratorModel) {
val table = Table(
UnitValue.createPointArray(
floatArrayOf(
100f,
160f
)
)
)
table.addCell(Paragraph("Total Credit").setBold())
table.addCell(Paragraph(info.totalCredit + ""))
table.addCell(Paragraph("Total Debit").setBold())
table.addCell(Paragraph(info.totalDebit + ""))
table.addCell(Paragraph("Total Profit").setBold())
table.addCell(Paragraph(info.totalProfit + ""))
layoutDocument.add(table)
}
private fun addSubHeading(layoutDocument: Document, text: String) {
layoutDocument.add(
Paragraph(text).setBold()
.setTextAlignment(TextAlignment.CENTER)
)
}
private fun addLink(layoutDocument: Document, text: String) {
val blueText: Text = Text(text)
.setFontColor(ColorConstants.BLUE)
.setFont(PdfFontFactory.createFont(StandardFonts.HELVETICA_BOLD))
layoutDocument.add(
Paragraph(blueText)
.setAction(PdfAction.createURI(text))
.setTextAlignment(TextAlignment.CENTER)
.setUnderline()
.setItalic()
)
}
private fun addTitle(layoutDocument: Document, text: String) {
layoutDocument.add(
Paragraph(text).setBold().setUnderline()
.setTextAlignment(TextAlignment.CENTER)
)
}
}
RPdfGeneratorModel
class RPdfGeneratorModel(list: List<RTransaction>, header: String) {
var list = emptyList<RTransaction>()
var header = ""
var totalCredit = ""
var totalDebit = ""
var totalProfit = ""
init {
this.list = list
this.header = header
calculateTotal(list)
}
private fun calculateTotal(items: List<RTransaction>) {
val totalPlus = items.map {
if (it.transType == RTransactionType.plus) {
it.totalPrice
} else { 0.0 }
}.sum()
val totalMinus = items.map {
if (it.transType == RTransactionType.minus) {
it.totalPrice
} else { 0.0 }
}.sum()
val final = totalPlus - totalMinus
totalDebit = "-" + totalMinus.toString()
totalCredit = totalPlus.toString()
totalProfit = final.toString()
}
}
RTransaction 模型
enum class RTransactionType { plus, minus }
class RTransaction {
var itemName: String = ""
var custName: String = ""
var transType: RTransactionType = RTransactionType.plus
var pricePerUnit: Double = 0.0
var quantity: Int = 0
var totalPrice: Double = 0.0
var transactionDateStr: String = ""
constructor() {
}
}
在您的活动类中编写以下函数以创建虚拟数据
private fun dummyModel(): RPdfGeneratorModel {
val list = dummyTransactions()
val header = "Statement"
val dummy = RPdfGeneratorModel(list, header)
return dummy
}
private fun dummyTransactions(): List<RTransaction> {
val list = arrayListOf<RTransaction>()
val i1 = RTransaction()
i1.custName = "Johan Store"
i1.itemName = "Snacks"
i1.quantity = 4
i1.pricePerUnit = 40.0
i1.totalPrice = i1.quantity * i1.pricePerUnit
i1.transactionDateStr = "10 Sep, 20"
i1.transType = RTransactionType.plus
list.add(i1)
val i2 = RTransaction()
i2.custName = "Alice Store"
i2.itemName = "Chocolate"
i2.quantity = 3
i2.pricePerUnit = 79.0
i2.totalPrice = i2.quantity * i2.pricePerUnit
i2.transactionDateStr = "9 Sep, 20"
i2.transType = RTransactionType.plus
list.add(i2)
val i3 = RTransaction()
i3.custName = "Alexa Mall"
i3.itemName = "Shoes"
i3.quantity = 2
i3.pricePerUnit = 177.0
i3.totalPrice = i3.quantity * i3.pricePerUnit
i3.transactionDateStr = "9 Sep, 20"
i3.transType = RTransactionType.minus
list.add(i3)
val i4 = RTransaction()
i4.custName = "Zainab Baba"
i4.itemName = "Chips"
i4.quantity = 5
i4.pricePerUnit = 140.0
i4.totalPrice = i4.quantity * i4.pricePerUnit
i4.transactionDateStr = "8 Sep, 20"
i4.transType = RTransactionType.plus
list.add(i4)
list.add(i1)
list.add(i2)
list.add(i3)
list.add(i4)
list.add(i1)
list.add(i2)
list.add(i3)
list.add(i4)
return list
}
现在调用 RPdfGenerator 函数。请务必在调用之前询问 WRITE_EXTERNAL_STORAGE 权限。更多详情请查看example project
val dummyInfo = dummyModel()
RPdfGenerator.generatePdf(this, dummyInfo)