You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter实现从Firebase实时数据库加载PDF并在App内查看

实现Flutter内联PDF查看功能

你已经引入了advance_pdf_viewer包,现在只需要补充PDF文档的加载状态管理和视图展示逻辑,就能在App内直接查看PDF,无需跳转外部浏览器。以下是修改后的完整方案:

修改说明

  • 新增专用PDF查看页面,用于展示加载后的PDF内容
  • 补充PDF加载流程的状态提示,优化用户体验
  • 处理加载失败的异常情况,给出友好提示

完整修改代码

import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_database/ui/firebase_animated_list.dart';
import 'package:flutter/material.dart';
import 'package:my_project/hello/Courses.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:advance_pdf_viewer/advance_pdf_viewer.dart';

class ViewCourses extends StatefulWidget {
  const ViewCourses({super.key});

  @override
  State<ViewCourses> createState() => _ViewCoursesState();
}

class _ViewCoursesState extends State<ViewCourses> {
  Query dbRef = FirebaseDatabase.instance.ref().child('Students');
  DatabaseReference reference = FirebaseDatabase.instance.ref().child('Students');

  Widget listItem({required Map student}) {
    if (!mounted) return Container();
    return SingleChildScrollView(
      child: GestureDetector(
        onTap: () {},
        child: Container(
          margin: const EdgeInsets.all(10),
          padding: const EdgeInsets.all(10),
          height: 300,
          color: const Color.fromARGB(255, 255, 200, 0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                (student['Course'] ?? "").toString(),
                style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
              ),
              const SizedBox(height: 5),
              Text(
                (student['Title'] ?? "").toString(),
                style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
              ),
              const SizedBox(height: 5),
              Text(
                (student['CreatedBy'] ?? "").toString(),
                style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
              ),
              Text(
                (student['file'] ?? "").toString(),
                style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.end,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  GestureDetector(
                    onTap: () {},
                    child: Row(
                      children: [
                        Icon(
                          Icons.edit,
                          color: Theme.of(context).primaryColor,
                        ),
                      ],
                    ),
                  ),
                  const SizedBox(width: 6),
                  GestureDetector(
                    onTap: () {
                      reference.child(student['key']).remove();
                    },
                    child: Row(
                      children: [
                        Icon(
                          Icons.delete,
                          color: Colors.red[700],
                        ),
                      ],
                    ),
                  ),
                  ElevatedButton(
                    onPressed: () async {
                      // 显示加载提示弹窗
                      showDialog(
                        context: context,
                        barrierDismissible: false,
                        builder: (context) => const Center(child: CircularProgressIndicator()),
                      );

                      try {
                        // 从URL加载PDF文档
                        final pdfDoc = await PDFDocument.fromURL(student['file']);
                        // 关闭加载弹窗并跳转到PDF查看页
                        Navigator.pop(context);
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (context) => PDFViewerPage(pdfDocument: pdfDoc),
                          ),
                        );
                      } catch (e) {
                        // 加载失败时关闭弹窗并提示错误
                        Navigator.pop(context);
                        ScaffoldMessenger.of(context).showSnackBar(
                          SnackBar(content: Text('PDF加载失败: ${e.toString()}')),
                        );
                      }
                    },
                    child: const Text('查看PDF'),
                  ),
                ],
              )
            ],
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('课程列表'),
      ),
      body: Container(
        height: double.infinity,
        child: FirebaseAnimatedList(
          query: dbRef,
          itemBuilder: (BuildContext context, DataSnapshot snapshot, Animation<double> animation, int index) {
            Map student = snapshot.value as Map;
            student['key'] = snapshot.key;
            return listItem(student: student);
          },
        ),
      ),
    );
  }
}

// 新增的PDF查看页面组件
class PDFViewerPage extends StatelessWidget {
  final PDFDocument pdfDocument;

  const PDFViewerPage({super.key, required this.pdfDocument});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('PDF查看器')),
      body: PDFViewer(
        document: pdfDocument,
        zoomSteps: 1,
        // 可自定义配置:默认缩放比例、页面导航、滚动模式等
      ),
    );
  }
}

关键修改点

  1. 加载状态管理:点击按钮后弹出加载指示器,避免用户等待时无反馈
  2. PDF视图组件:新增PDFViewerPage页面,使用PDFViewer控件渲染加载完成的PDF文档
  3. 异常处理:通过try-catch捕获加载失败的情况,用SnackBar提示用户具体错误
  4. 交互优化:将按钮文本改为更直观的"查看PDF",提升操作辨识度

内容的提问来源于stack exchange,提问作者Rae Sherchan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 18:05:16