如何将Android XML布局转换为PDF?尝试现有教程效果不佳,希望通过截图实现
Android XML布局转PDF实现方案
现有代码问题
- 重复声明
Bitmap变量:方法内重新定义了和成员变量同名的bitmap,会导致取值逻辑异常 - 缺失XML布局转Bitmap的核心步骤,没有实现XML布局截图逻辑
- 未适配Android7.0及以上系统的文件访问规则,直接调用
Uri.fromFile会触发FileUriExposedException崩溃 - 存储路径合法性校验不全,未做权限获取判断逻辑
完整实现步骤
- 先对目标XML布局生成截图Bitmap
- 修正PDF生成逻辑,修复变量重复定义问题
- 适配高版本系统的PDF文件打开权限
可用实现代码
1. XML布局转Bitmap方法
// 针对已经渲染在当前页面的View生成截图 private Bitmap getBitmapFromView(View view) { Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); view.draw(canvas); return bitmap; } // 针对未渲染的XML布局文件生成截图 private Bitmap getBitmapFromXml(int layoutId) { View view = LayoutInflater.from(this).inflate(layoutId, null); view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); view.draw(canvas); return bitmap; }
2. 修正后的PDF生成方法
private void createPdf() { // 替换为你自己的目标XML布局ID,或者传入已经渲染的View对象获取Bitmap Bitmap bitmap = getBitmapFromXml(R.layout.your_target_layout); PdfDocument document = new PdfDocument(); PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(bitmap.getWidth(), bitmap.getHeight(), 1).create(); PdfDocument.Page page = document.startPage(pageInfo); Canvas canvas = page.getCanvas(); Paint paint = new Paint(); paint.setColor(Color.parseColor("#ffffff")); canvas.drawPaint(paint); canvas.drawBitmap(bitmap, 0, 0, paint); document.finishPage(page); // 默认存入公共下载目录,避免权限适配问题 String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(); File file = new File(path); if (!file.exists()) { file.mkdirs(); } String targetPdf = path + File.separator + "test-2.pdf"; File filePath = new File(targetPdf); try { document.writeTo(new FileOutputStream(filePath)); Toast.makeText(this, "PDF生成成功,存储路径:" + targetPdf, Toast.LENGTH_LONG).show(); // 生成成功后直接打开PDF openPdf(targetPdf); } catch (IOException e) { Log.e("PDF生成", "错误信息: " + e.toString()); Toast.makeText(this, "生成失败:" + e.toString(), Toast.LENGTH_LONG).show(); } document.close(); bitmap.recycle(); // 及时回收Bitmap避免内存泄漏 }
3. 适配高版本系统的PDF打开方法
首先需要在AndroidManifest.xml中配置FileProvider适配文件访问:
<application> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
在res/xml目录下新建file_paths.xml文件:
<?xml version="1.0" encoding="utf-8"?> <paths> <external-path name="download" path="Download/" /> </paths>
修正后的openPdf方法:
private void openPdf(String path) { File file = new File(path); Intent target = new Intent(Intent.ACTION_VIEW); Uri uri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { uri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", file); target.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { uri = Uri.fromFile(file); } target.setDataAndType(uri, "application/pdf"); target.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); Intent intent = Intent.createChooser(target, "打开PDF文件"); try{ startActivity(intent); }catch (ActivityNotFoundException e){ Toast.makeText(this, "没有安装可以打开PDF的应用", Toast.LENGTH_SHORT).show(); } }
注意事项
- Android 12及以下版本需要动态申请
WRITE_EXTERNAL_STORAGE权限,Android13及以上不需要额外存储权限即可写入公共下载目录 - 如果布局尺寸过大,可以适当缩放Bitmap大小,降低PDF文件体积
内容的提问来源于stack exchange,提问作者anmol dhillon
相关产品推荐
相关产品推荐

