PDF 在 Flutter 应用程序中不可见:flutter_pdf_view

问题描述 投票:0回答:1

我正在开发一个 flutter 应用程序,想在我的应用程序中显示 PDF。 pdf 是使用 URL 下载的,可通过 API 获取该 URL。文档 URL 示例为:

https://drive.google.com/uc?export=view&id=GHwcjxgvKNYU3HuNsdajkdn5

import 'dart:developer';
import 'dart:io';

import 'package:dio/dio.dart' as dio;
import 'package:dio/dio.dart';
import 'package:get/get.dart';

import '../constants/appConstants/AppConstants.dart';
import '../constants/appConstants/Urls.dart';
import '../util/SecureStorage.dart';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';

class AlertController extends GetxController {
  final SecureStorage _secureStorage = SecureStorage();

  final _dio = dio.Dio();

  RxList<Map<String, dynamic>> alerts = <Map<String, dynamic>>[].obs;
  RxMap<String, dynamic> alertDetails = <String, dynamic>{}.obs;
  RxBool isLoadingDetails = false.obs;
  Rx<File?> document = Rx<File?>(null);

  Future<int> loadAlertDetails({required String alertToken}) async {
    String? token = await _secureStorage.readAccessToken();
    isLoadingDetails.value = true;
    Options options = Options(
        validateStatus: (_) => true,
        contentType: Headers.jsonContentType,
        responseType: ResponseType.json,
        headers: {HttpHeaders.authorizationHeader: token!});
    try {
      dio.Response response = await _dio.get(alertDetailsUrl,
          options: options, queryParameters: {"token": alertToken});

      Map<String, dynamic> responseData = response.data;
      if (responseData.isNotEmpty) {
        if (responseData['code'] == 2000) {
          alertDetails.value = responseData['data'];
          File? docFile =
              await _checkForDoc(); // Assign to nullable File variable
          document = Rx<File?>(docFile);
          ; // Assign nullable File variable to nullable Rx variable
          // log('response: ${responseData['data']}  ${document!.value}');
        }
        isLoadingDetails.value = false;
        return responseData['code'];
      }
    } catch (err) {
      log(err.toString());
    }
    isLoadingDetails.value = false;
    return -1;
  }

  Future<File?> _checkForDoc() async {
    if (alertDetails['alertInputType'] == AlertInputType.document.value) {
      if (alertDetails['alertDocuments'] != null &&
          alertDetails['alertDocuments'].length > 0) {
        final response = await http
            .get(Uri.parse(alertDetails['alertDocuments'][0]['documentUrl']));
        final bytes = response.bodyBytes;
        File? file = await _storeFile(
            alertDetails['alertDocuments'][0]['documentUrl'], bytes);
        return file;
      }
    }
    return null;
  }

  Future<File?> _storeFile(String url, List<int> bytes) async {
    try {
      final filename = alertDetails['alertDocuments'][0]['documentName'];
      final dir = await getApplicationDocumentsDirectory();

      final file = File('${dir.path}/$filename');
      await file.writeAsBytes(bytes, flush: true);
      log(file.path);
      return file;
    } catch (error) {
      log('Error storing file: $error');
      return null; // Return null if file cannot be stored
    }
  }
}

我确信该文件已正确下载,并且可以获得该文件的路径(如下所示)。

File: '/data/user/0/com.example.cacmp_app/app_flutter/demo.pdf'

逻辑是这样的,当alertInputType==DOCUMENT时,我用PDF显示详细信息,否则我用图像显示详细信息:

import 'dart:developer';

import 'package:cacmp_app/constants/appConstants/AppConstants.dart';
import 'package:cacmp_app/constants/themes/ColorConstants.dart';
import 'package:cacmp_app/constants/widgets/AppSnackbar.dart';
import 'package:cacmp_app/constants/widgets/CustomLoadingIndicator2.dart';
import 'package:cacmp_app/pages/LoginPage.dart';
import 'package:cacmp_app/stateUtil/AlertController.dart';
import 'package:cacmp_app/util/DateFormatUtil.dart';
import 'package:cacmp_app/util/SecureStorage.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:flutter_pdfview/flutter_pdfview.dart';
import '../constants/widgets/DetailsImageContainer.dart';
import '../constants/widgets/DetailsItems.dart';

class AlertDetailsPage extends StatefulWidget {
  final String alertToken;
  const AlertDetailsPage({super.key, required this.alertToken});

  @override
  State<AlertDetailsPage> createState() => _AlertDetailsPageState();
}

class _AlertDetailsPageState extends State<AlertDetailsPage> {
  final AlertController _alertController = Get.find();
  final SecureStorage _secureStorage = SecureStorage();

  PDFViewController? controller;
  int pages = 0;
  int indexPage = 0;

  @override
  void initState() {
    super.initState();
    _loadDetails();
  }

  void _loadDetails() async {
    final int code =
        await _alertController.loadAlertDetails(alertToken: widget.alertToken);
    log('details response code: $code');
    if (code == 2000) {
    } else if (code == 2003) {
      _secureStorage.deleteOnLogOut();
      Get.offAll(() => const LoginPage());
      AppSnackbar.showSnackbar(title: "Expired!", description: "Login again!");
    } else {
      AppSnackbar.showSnackbar(
          title: "Failed!", description: "Cannot load data!");
    }
  }

  final AppBar _appBar = AppBar(
    title: const Text('Details'),
  );

  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
      statusBarColor: kPrimaryColor,
      statusBarIconBrightness: Brightness.light,
      systemStatusBarContrastEnforced: true,
      systemNavigationBarColor: kPrimaryColor,
      systemNavigationBarIconBrightness: Brightness.light,
      systemNavigationBarDividerColor: Colors.white,
    ));

    final height = MediaQuery.of(context).size.height -
        _appBar.preferredSize.height -
        MediaQuery.of(context).padding.top -
        MediaQuery.of(context).padding.bottom;
    final width = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: _appBar,
      body: Obx(
        () => SingleChildScrollView(
          child: (_alertController.isLoadingDetails.value)
              ? CustomLoadingIndicator2(color: kPrimaryColor)
              : Padding(
                  padding: EdgeInsets.symmetric(horizontal: width * 0.02),
                  child: (_alertController
                              .alertDetails.value['alertInputType'] ==
                          AlertInputType.text.value)
                      ? Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            (_alertController.alertDetails.value['alertImages']
                                        .length >
                                    0)
                                ? Container(
                                    height: height * 0.3,
                                    width: width,
                                    padding: EdgeInsets.symmetric(
                                        horizontal: width * 0.05,
                                        vertical: height * 0.01),
                                    child: CarouselSlider(
                                      items: _alertController
                                          .alertDetails.value['alertImages']
                                          .map<Widget>((url) {
                                        return DetailsImageContainer(
                                            height: height,
                                            width: width,
                                            imageUrl: url);
                                      }).toList(),
                                      options: CarouselOptions(
                                          autoPlay: false,
                                          aspectRatio: 16 / 9,
                                          enlargeCenterPage: true,
                                          pauseAutoPlayOnTouch: true,
                                          autoPlayInterval:
                                              const Duration(seconds: 3),
                                          autoPlayAnimationDuration:
                                              const Duration(milliseconds: 800),
                                          viewportFraction: 0.8,
                                          onPageChanged: (index, reason) {},
                                          scrollPhysics:
                                              const BouncingScrollPhysics()),
                                    ),
                                  )
                                : Container(),
                            Padding(
                              padding: const EdgeInsets.all(10.0),
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Text(
                                    'Details',
                                    style:
                                        Theme.of(context).textTheme.bodyMedium,
                                  ),
                                  const SizedBox(height: 10),
                                  DetailsItem(
                                    title: 'Subject',
                                    value: _alertController
                                        .alertDetails.value['subject'],
                                  ),
                                  DetailsItem(
                                    title: 'Description',
                                    value: _alertController
                                        .alertDetails.value['message'],
                                  ),
                                  DetailsItem(
                                    title: 'Published On',
                                    value: formatDate(DateTime.parse(
                                        _alertController.alertDetails
                                            .value['publishedOn'])),
                                  ),
                                ],
                              ),
                            ),
                          ],
                        )
                      : (_alertController.document.value != null)
                          ? Column(
                              mainAxisAlignment: MainAxisAlignment.start,
                              crossAxisAlignment: CrossAxisAlignment.center,
                              children: [
                                Container(
                                  width: width,
                                  height: height * 0.1,
                                  alignment: Alignment.centerLeft,
                                  child: Text(
                                    'Details',
                                    style:
                                        Theme.of(context).textTheme.bodyLarge,
                                  ),
                                ),
                                DetailsItem(
                                  title: 'Subject',
                                  value: _alertController
                                      .alertDetails.value['subject'],
                                ),
                                DetailsItem(
                                  title: 'Published On',
                                  value: formatDate(DateTime.parse(
                                      _alertController
                                          .alertDetails.value['publishedOn'])),
                                ),
                                Container(
                                  color: Colors.red,
                                  height: height * 0.5,
                                  child: PDFView(
                                    filePath:
                                        _alertController.document.value!.path,
                                    autoSpacing: false,
                                    swipeHorizontal: true,
                                    pageSnap: false,
                                    pageFling: false,
                                    onRender: (pages) =>
                                        setState(() => this.pages = pages!),
                                    onViewCreated: (controller) => setState(
                                        () => this.controller = controller),
                                    onPageChanged: (indexPage, _) => setState(
                                        () => this.indexPage = indexPage!),
                                  ),
                                )
                              ],
                            )
                          : Container(),
                ),
        ),
      ),
    );
  }
}

当“alertInputType”为“DOCUMENT”时,将渲染 PDFView,显示 PDF。但是,只有 PDFView 框得到渲染,PDF 不可见。 我从下面的例子中采用了这个方法-
https://github.com/JohannesMilke/pdf_viewer_example/blob/master/lib/page/pdf_viewer_page.dart
https://www.youtube.com/watch?v=uizZbJWziEg&ab_channel=HeyFlutter%E2%80%A4com

这是我的页面截图-

我正在使用以下软件包(如上面的示例)-

flutter_pdfview: ^1.2.7  
  path: ^1.7.0  
  path_provider: ^1.6.27  

请帮忙!

android flutter file pdf flutter-getx
1个回答
0
投票

使用这个包--->syncfusion_flutter_pdfviewer:^25.1.38

© www.soinside.com 2019 - 2024. All rights reserved.