flutter实践pdf的简单介绍

Flutter——pdf阅读功能的实现

实现pdf阅读、横竖屏切换,以及pdf页面的点击放大和双指放大等功能

成都创新互联专业IDC数据服务器托管提供商,专业提供成都服务器托管,服务器租用,成都服务器托管成都服务器托管,成都多线服务器托管等服务器托管服务。

在这个项目中使用的是 flutter_plugin_pdf_viewer: ^1.0.7 ,可以满足我们最基本的pdf需求阅读需求。所做的满足项目需求的工作主要是横竖屏切换功能,以及我们的初始化继续阅读等等。

首先导入插件部分源码

插件所提供的示例,已经满足了最基本的图片放大、横屏阅读的功能,我们工作的难点就在于pdf竖屏阅读的实现,所以我们需要解决的问题主要有以下几点:

(1) 横屏加载同一页面不能重复流量加载

(2) 切换竖屏时加载速度不能过慢,页面不能有断层

(3) 横竖屏切换时页码的定位保持

针对于上述问题,我们一一进行解决。

重复流量加载 ,解决这一问题比较简单,我们可以利用缓存实现,在每一次加载pdf页时,存储其(key,value),这样在下一次加载时我们会判断这个页面在缓存中是否已经存在,不存在重新加载,存在则调用缓存中的数据,页面销毁时清除所有缓存即可。

切换横竖屏 ,竖屏PDF阅读的实现,思路就是将所有横屏页面存在list中,使用LIstView.builder()进行绘制,这种方法存在的缺点就是太慢了,需要将所有页面全部加载之后,才可以绘制页面,用户体验非常差,所以我们需要做一些改进,为了提升加载速度,实现效果GIF中的效果,我们就要使用FutureBuilder()方法,来实现预加载功能,具体实现如下:

(在这里不对此组件过多介绍,后续会专门介绍此组件的使用),这样我们就可以实现预加载的功能了。

横竖屏切换定位 ,这个点的解决思路已经在我的 (Flutter 初始化ListView定位子组件位置) 中进行了介绍,实现了解决。

至此,我们就解决了所有的难点问题。

Flutter Boost 接入实践(iOS 篇)

本文将简单梳理一下 iOS 工程接入的 Flutter Boost 的流程,以作为前文的补充。

flutter_application_path = '../flutter_module'

load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

target 'FlutterHybridiOS' do

install_all_flutter_pods(flutter_application_path)

end

接着在工程根目录下运行 pod install ,即可集成上 Flutter Module。看到我们的 Pods 中多了以下几个模块,即说明集成成功。

接着在工程根目录下运行 pod install ,即可集成上 Flutter Module。看到我们的 Pods 中多了以下几个模块,即说明集成成功。

这一块直接参照 Flutter Boost 官方提供的 example 就好了:

PlatformRouterImp.h:

PlatformRouterImp.m:

可以看到,Flutter Boost 支持常规 push,也支持打开模态弹窗,也支持手动 pop。

AppDelegate.h:

AppDelegate.m:

同样的,这里可在 Native 端用两种不同的方式去打开我们在 Flutter Module 中注册好的路由名。

至此,我们成功在 iOS 工程中接入了 Flutter Boost,那就开启我们的混编之旅吧~

Flutter实践--屏幕适配

做移动端开发的小伙伴都知道,针对不同型号和尺寸的手机要进行页面适配,且Android和iOS适配方案各不相同,那flutter端如何进行适配呢?以下为近期flutter开发过程中关于适配的一些学习和记录~~~~

说到flutter屏幕适配,就不得不提到插件 flutter_screenutil ,提到flutter_screenutil就不得不说以下几点????

默认宽1080px

默认高1920px

allowFontScaling为false,即不跟随系统字体大小设置变化

初始化单位为px

需要把context传进去,因为内部是通过 MediaQuery 来获取屏幕尺寸等相关信息的

无需再传context,因为内部是通过单例 window 来获取屏幕尺寸等相关信息的

作为iOS开发,之前都是以pt为参照进行比例适配的,且架构组已经定义了一套适配相关常量,传px进去不太方便,所以需要对flutter_screenutil进行扩展

公司设计图是以iPhone X的尺寸提供的即物理设备尺寸为375x812,像素比例为750x1624,像素密度比为2

初始化仍用px来初始化

dart sdk 2.7正式支持 extension-method ,即为已有类扩展方法,从 flutter_screenutil 这种 540.w 写法点进去,我们可以看到

flutter_screenutil为num类扩展了一系列简写方法,那我们当然可以按照它这种方式进行扩展

网上提供的解决方案:

第一步:修改 pubspec.yaml

第二步:执行 flutter pub get

第三步:重启 AndroidStudio

解决方案:去掉const即可

UI设计中px、pt、ppi、dpi、dp、sp之间的关系

Dart/Flutter - 扩展方法(ExtensionMethod)

PDF文件生成

PDF(Portable Document Format)是Adobe公司发明的一种文档格式,由于其具有很多独特的优点而被广泛使用。如pdf可内嵌字体,这样就可以避免客户端没有安装字体而显示不一致;如pdf的图片和文字使用了矢量图,这样就可以随意放大而不会失真;另外pdf的加密和防篡改也是一大亮点,是向外发布资料的首选格式

一个未经修改的PDF文件从头到尾主要包括4个部分,分别是:文件头、对象集合、交叉引用表、文件尾。其中:

%PDF-1.4

1 0 obj

/Producer (Skia/PDF m92)

endobj

xref

0 83

0000000000 65535 f

0000000015 00000 n

0000010954 00000 n

trailer

/Size 83

/Root 11 0 R

/Info 1 0 R

startxref

50152

%%EOF

iOS可以通过UIGraphicsPDFRenderer类生成PDF,其本身的api非常简单:一个init方法,一个写入文件的方法,一个导出data数据的方法

用于构造UIGraphicsPDFRenderer,第一个参数是pdf的尺寸,第二个参数可以设置pdf文件的元数据

生成pdf并写入到指定URL

生成pdf并返回Data

绘制PDF主要依靠 UIGraphicsPDFRendererContext ,这是UIGraphicsRendererContext的子类,所以iOS是使用CoreGraphics的draw api进行pdf绘制的

除了CoreGraphics的相关api之外,最重要的是 func beginPage() ,用于创建一页pdf

安卓可以使用 PdfDocument 类生成PDF,和iOS类似,采用了系统的绘图api( Canvas ),对于开发者来说学习成本很低。但是安卓的坑比较多,建议采用iText、PDFBox等第三方实现。如drawText不支持多行文本,要通过较复杂的操作来实现;某些系统对文档内的图片不进行压缩,导致生成的pdf比正常的大10多倍

flutter可以使用 pdf库 生成pdf,该库实现了一套自己的widgets,开发者可以像写普通widgets一样去写pdf;另外还提供了table相关的api,不用手动画表格,还支持自动分页,非常友好。

Flutter PDF阅读,可显示页数,源码

添加flutter_pdfview: ^1.2.1 组件

class PDFScreenextends StatefulWidget {

final Stringurl;

final Stringpath;

final Stringtitle;

PDFScreen({Key key,this.url, this.path, this.title}) :super(key: key);

_PDFScreenStatecreateState() =_PDFScreenState();

}

class _PDFScreenStateextends Statewith WidgetsBindingObserver {

final Completer_controller =

Completer();

intpages =0;

intcurrentPage =0;

boolisReady =false;

StringerrorMessage ='';

@override

Widgetbuild(BuildContext context) {

return Scaffold(

appBar:AppBar(

elevation:0,

    leading:new IconButton(

icon:Image.asset(

Utils.getImgPath('icon_back'),

        width:18,

        height:36,

      ),

      onPressed: () {

Navigator.of(context).pop();

      },

    ),

    centerTitle:true,

    title:Text(

widget.title,

      style:TextStyle(fontSize:17.0),

    ),

  ),

  body:Stack(

children: [

Positioned(

height: MediaQuery.of(context).size.height - (Utils.getHeightSize(80, context) *2),

          width: MediaQuery.of(context).size.width,

          child:PDFView(

filePath:widget.path,

            enableSwipe:true,

            swipeHorizontal:true,

            autoSpacing:false,

            pageFling:true,

            pageSnap:true,

            defaultPage:currentPage,

            fitPolicy: FitPolicy.BOTH,

            preventLinkNavigation:

false, // if set to true the link is handled in flutter

            onRender: (_pages) {

setState(() {

pages = _pages;

                isReady =true;

              });

            },

            onError: (error) {

setState(() {

errorMessage = error.toString();

              });

              print(error.toString());

            },

            onPageError: (page, error) {

setState(() {

errorMessage ='$page: ${error.toString()}';

              });

              print('$page: ${error.toString()}');

            },

            onViewCreated: (PDFViewController pdfViewController) {

_controller.complete(pdfViewController);

            },

            onLinkHandler: (String uri) {

print('goto uri: $uri');

            },

            onPageChanged: (int page, int total) {

print('page change: $page/$total');

              setState(() {

currentPage = page;

              });

            },

          ),

      ),

      Positioned(

bottom:0,

          height: Utils.getHeightSize(80, context),

          width: MediaQuery.of(context).size.width,

          child:Container(

// padding: EdgeInsets.only(left: 10.0, right: 10.0,top: 10.0,bottom: 10.0),

            decoration:BoxDecoration(

color: Colors.white,

              border:Border.all(color: AppColors.shadeGary),

              boxShadow: [

//refer to :

                BoxShadow(

color: AppColors.shadeGary,

                    offset:Offset(0.0, 0.0),

                    blurRadius:3.0,

                    spreadRadius:0.0),

              ],

            ),

            child:Stack(

children: [

Row(

mainAxisSize: MainAxisSize.min,

                  children: [

Container(),

                    Expanded(child:SizedBox()),

                    Container(

height:42.0,

                      width: Utils.getWidthSize(90, context),

                      margin:EdgeInsets.only(right:20.0,bottom:5.0),

                      decoration:BoxDecoration(//边框线

                        borderRadius:BorderRadius.circular(21.0),  //圆角

                        gradient:LinearGradient(

colors: [Color(0xFF5FD27A), Color(0xFF3FAF6F)],

                        ),

                      ),

                      child:TextButton(

style:ButtonStyle(

overlayColor: MaterialStateProperty.all(Colors.transparent),

                          foregroundColor: MaterialStateProperty.resolveWith(

(states) {

if (states.contains(MaterialState.pressed)) {

//按下时的颜色

                                return Colors.transparent;

                              }

//默认状态使用灰色

                              return Colors.transparent;

                            },

                          ),

                        ),

                        child:Text(

globalTranslations.text("msg_download"),

                          style:TextStyle(color: Colors.white),

                        ),

                        onPressed: () {

launchPdfURL(widget.url);

                        },

                      ),

                    ),

                  ],

                ),

              ],

            ),

          )),

      errorMessage.isEmpty

          ? !isReady

          ?Center(

child:CircularProgressIndicator(),

      )

:Container()

:Center(

child:Text(errorMessage),

      )

],

  ),

  // floatingActionButton: FutureBuilder(

//  future: _controller.future,

//  builder: (context, AsyncSnapshot snapshot) {

//    if (snapshot.hasData) {

//      return FloatingActionButton.extended(

//        label: Text("Go to ${pages ~/ 2}"),

//        onPressed: () async {

//          await snapshot.data.setPage(pages ~/ 2);

//        },

//      );

//    }

//

//    return Container();

//  },

// ),

);

}

launchPdfURL(String url) {

launch(url);

}

}


名称栏目:flutter实践pdf的简单介绍
文章链接:http://abwzjs.com/article/dsihosp.html