Flutter手冊.pdf,flutter基礎(chǔ)教程

PDF文件生成

PDF(Portable Document Format)是Adobe公司發(fā)明的一種文檔格式,由于其具有很多獨特的優(yōu)點而被廣泛使用。如pdf可內(nèi)嵌字體,這樣就可以避免客戶端沒有安裝字體而顯示不一致;如pdf的圖片和文字使用了矢量圖,這樣就可以隨意放大而不會失真;另外pdf的加密和防篡改也是一大亮點,是向外發(fā)布資料的首選格式

創(chuàng)新互聯(lián)建站-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價比建始網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式建始網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋建始地區(qū)。費用合理售后完善,10余年實體公司更值得信賴。

一個未經(jīng)修改的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方法,一個寫入文件的方法,一個導(dǎo)出data數(shù)據(jù)的方法

用于構(gòu)造UIGraphicsPDFRenderer,第一個參數(shù)是pdf的尺寸,第二個參數(shù)可以設(shè)置pdf文件的元數(shù)據(jù)

生成pdf并寫入到指定URL

生成pdf并返回Data

繪制PDF主要依靠 UIGraphicsPDFRendererContext ,這是UIGraphicsRendererContext的子類,所以iOS是使用CoreGraphics的draw api進行pdf繪制的

除了CoreGraphics的相關(guān)api之外,最重要的是 func beginPage() ,用于創(chuàng)建一頁pdf

安卓可以使用 PdfDocument 類生成PDF,和iOS類似,采用了系統(tǒng)的繪圖api( Canvas ),對于開發(fā)者來說學(xué)習(xí)成本很低。但是安卓的坑比較多,建議采用iText、PDFBox等第三方實現(xiàn)。如drawText不支持多行文本,要通過較復(fù)雜的操作來實現(xiàn);某些系統(tǒng)對文檔內(nèi)的圖片不進行壓縮,導(dǎo)致生成的pdf比正常的大10多倍

flutter可以使用 pdf庫 生成pdf,該庫實現(xiàn)了一套自己的widgets,開發(fā)者可以像寫普通widgets一樣去寫pdf;另外還提供了table相關(guān)的api,不用手動畫表格,還支持自動分頁,非常友好。

系統(tǒng)找不到指定的路徑怎么解決?

1.首先,請按“Win+R”鍵輸入“Services.msc”回車打開服務(wù);

2.以Windows Firewall為例,右擊點擊屬性;

3.即可查看服務(wù)對應(yīng)的可運行文件路徑;

4.接著回到桌面,按“Win+R”鍵輸入“regedit”回車打開注冊表;

5.接下來定位到HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/MpsSvc;

6.雙擊并確認ImagePath的數(shù)值數(shù)據(jù)是否相同,如"%SystemRoot%/system32/svchost.exe

-k LocalServiceNoNetwork";

7.如不同,可設(shè)置相同完成后重新啟動計算機,即可以解決系統(tǒng)找不到指定路徑”問題。

Flutter PDF閱讀,可顯示頁數(shù),源碼

添加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;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

//默認狀態(tài)使用灰色

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 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);

}

}

Android真的推薦用MVI模式?MVI和MVVM有什么區(qū)別?

android自己卷自己,自己造一個MVI架構(gòu)模式嗎?

MVI架構(gòu)模式是國內(nèi)android開發(fā)者最近一兩年造出來的嗎?

看了很多MVI的資料,發(fā)現(xiàn)都提到cycle.js框架。android的mvi架構(gòu)就是啟發(fā)于cycle.js框架。

我們再看看Cycle.js框架是什么時候開始的,又是什么時候開始使用MVI模式的。

Cycle.js框架 第一個預(yù)發(fā)版本 :

再結(jié)合官方文檔來看,Cycle.js框架就是為了MVI架構(gòu)模式而生的。

雖然不知道,Cycle.js框架是不是首個MVI模式框架。

但是從很多資料可以推測,MVI架構(gòu)模式就是Cycle.js框架推廣開來的。

而且早在2014年就已經(jīng)在前端開發(fā)中用得飛起了。

想想2014年,咱們在干嘛?android在用什么架構(gòu)模式。

正所謂,天下武功出少林啊。

我們android的很多技術(shù),在前端早就用“爛了”。

我們知道MVP和MVVM的爹都是MVC。MVI的爹也是MVC。

MVC的Controller是命令是編程組件,不能直接實現(xiàn)響應(yīng)式編程思想。

響應(yīng)式編程范式(Reactive programming):

安卓官方的compose框架、微信小程序、Flutter、React、鴻蒙UI的開發(fā)框架,都是使用響應(yīng)式開發(fā)框架。

這里就不拓展開來講了,上面提到的任何一個開發(fā)框架,你只要會一個基本就能理解響應(yīng)式編程范式。

如果一個都不會也沒關(guān)系,現(xiàn)在不理解響應(yīng)式編程也沒關(guān)系,等你學(xué)會MVI就理解了,這種只有實際使用過才能深刻理解。

學(xué)不會也沒關(guān)系,不要焦慮(尤其那些工作不久的小伙伴,學(xué)不會屬于正?,F(xiàn)象~)

MVI,咱第一遍學(xué)不會,就等2年,再學(xué)一遍~

2年后也沒學(xué)會,那就再等2年~ 一定要有耐心~

如果還是學(xué)不會,那也沒關(guān)系,因為MVI早晚也會過時~ 等過時了就不用學(xué)了~

哈哈哈~ 別笑,正經(jīng)Android可不會開玩笑的。

就像rxjava,當(dāng)年有多少人死活學(xué)不會,android開發(fā)現(xiàn)在誰還學(xué)Rxjava?哈哈哈~

用一張圖來總結(jié)這次升級的核心思想:

新版架構(gòu)指南在舊版的基礎(chǔ)上,做了如下調(diào)整和建議:

1. 將LiveData組件改成了StateFlow

對協(xié)程的使用更友好。并且更能體現(xiàn)面向數(shù)據(jù)流開發(fā)的思想。

實際上,依然使用LiveData也沒毛病。

2. ViewModel傳遞給View的數(shù)據(jù)限制為View的UIState

ViewModel從Model層獲取數(shù)據(jù)后,轉(zhuǎn)換為UIState數(shù)據(jù),通過StateFlow流向View層。

UIState的數(shù)據(jù)面向界面組件而定義的,是能直接控制View組件如何顯示的數(shù)據(jù)。

所以我們也可以稱UIState為界面的狀態(tài)或者View的狀態(tài)。

如下:

3. 單數(shù)據(jù)流還是多數(shù)據(jù)流的選擇

官方指南并沒有強制我們使用單流。

同一個界面應(yīng)該使用單個StateFlow還是多個StateFlow,需要我們自己判斷。

我們應(yīng)該根據(jù)UIStates數(shù)據(jù)們之間關(guān)聯(lián)程度來決定多流還是單流。

單流優(yōu)缺點都十分明顯:

優(yōu)點: 數(shù)據(jù)集中管控,會提高代碼的可讀性和修改的便利性。

缺點: 當(dāng)數(shù)據(jù)非常多且復(fù)雜時,會影響效率。因為我們沒有diff功能,View層不能只更新有變化的數(shù)據(jù),只會根據(jù)UIState刷新當(dāng)前界面。

我們再看下官方新版架構(gòu)圖:

當(dāng)然不僅僅MVVM可以改造成響應(yīng)式開發(fā)范式,MVP也是可以的。

不信你看 這篇blog :

1. 理解MVC架構(gòu)模式的思想【MVC是其他架構(gòu)模式之爹,他的思想是MVP、MVVM、MVI的基礎(chǔ),學(xué)會它是關(guān)鍵步驟~】。

3. 學(xué)習(xí)kotlin的StateFlow組件,的使用:Sequence-Flow-StateFlow。

4. 學(xué)習(xí)ViewModel組件的使用(雖然不用ViewModel也能實現(xiàn)MVI架構(gòu),但是ViewModel還是值得學(xué)習(xí))。

5. 理解DRY(Don't Repeat Yourself)原則。

6. 理解MVVM(因為官方的MVI模式是基于MVVM的基礎(chǔ)改造的~)。

7. 學(xué)習(xí)官方架構(gòu)指南。

8. 實戰(zhàn)。

在這里就分享一份由大佬親自收錄整理的 學(xué)習(xí)PDF+架構(gòu)視頻+面試文檔+源碼筆記 , 高級架構(gòu)技術(shù)進階腦圖、Android開發(fā)面試專題資料,高級進階架構(gòu)資料

這些都是我現(xiàn)在閑暇時還會反復(fù)翻閱的精品資料。里面對近幾年的大廠面試高頻知識點都有詳細的講解。相信可以有效地幫助大家掌握知識、理解原理,幫助大家在未來取得一份不錯的答卷。

當(dāng)然,你也可以拿去查漏補缺,提升自身的競爭力。

真心希望可以幫助到大家,Android路漫漫,共勉!

如果你有需要的話,只需 私信我【進階】即可獲取

Flutter入門-Dart面向?qū)ο笤?/h2>

Dart作為高級語言,支持面向?qū)ο蟮暮芏嗵匦?,并且支持基于mixin的繼承方式,基于mixin的繼承方式是指:一個類可以繼承自多個父類,相當(dāng)于其他語言里的多繼承。所有的類都有同一個基類Object,這和特性類似于Java語言,Java所有的類也都是繼承自O(shè)bject,也就是說一切皆對象。

Dart 是一門面向?qū)ο蟮恼Z言, 全部的類都是繼承自 Object , 除了支持傳統(tǒng)的 繼承、封裝、多態(tài) , 還有基于組合(Mixin-based)的繼承特性

類型推導(dǎo)(var/final/const)

var

final和const的區(qū)別

3.非零即真( )

4.字符串

5.集合

Dart中變量初始值為null,即使是int類型也可以是null(java中int默認是0, boolean默認是false); Dart支持自識別,可以是用var定義變量,也可以直接指定具體類型; final或者const都可修飾不可變的變量,final變量只能賦值一次,const是編譯時常量。

int和double是num子類,沒有float類型; 支持字符串模板,用${expression}的方式來實現(xiàn)字符串效果,類似如字符串拼接; String可以使用單引號或者雙引號; Dart沒有數(shù)組,只有列表; 其中List,Set,Map不是抽象接口,是具體實現(xiàn)類,可直接使用; Map的key沒有指定類型,key類型不一致不會報錯;key不能相同,但是value可以相同,value可以為null。 var name = 'Tom';

方法也是對象,方法可賦值給一個變量; 如果方法的參數(shù)是解構(gòu)出來的可以通過 @required 注解標(biāo)注為必填 const Scrollbar({Key key, @required Widget child}); 支持可選參數(shù),可選命名參數(shù)用{}包圍,可選位置參數(shù)寫在最后并且使用[]包圍 String say(String from, String msg, [String device]); 支持默認參數(shù) void enableFlags({bool bold = false, bool hidden = false}) {…}; 以_開頭的方法都是私有的。 void main() {

支持閉包,閉包能夠訪問外部方法內(nèi)部的局部變量

1.空替換?? expr1 ?? expr2,如果expr1是non-null,返回其值。否則執(zhí)行expr2并返回其結(jié)果; 2.條件成員訪問?.P?.y = 4; 如果p是non-null,則設(shè)置y的值等于4; 3.類型判定操作符(as,is,is!); 4.級聯(lián)操作,可以在同一個對象上連續(xù)調(diào)用多個函數(shù)以及訪問成員變量;

和java不同的是,Dart可以拋出任意類型的對象; 程序不會強制要求開發(fā)中處理異常,但若發(fā)生異常,程序會中斷; 其中異常主要分為Error和Exception兩種類型。

創(chuàng)建對象可以不使用new關(guān)鍵字; Dart中沒有public,private,protected這些關(guān)鍵字; 沒有interfaces關(guān)鍵字,每一個類都是一個接口。我們可以用抽象類來類比java中的接口; Dart把多重繼承的類叫做Mixins。

支持語法糖 Point(this.x, this.y); 每個實例變量都會自動生成一個getter方法,Non-final變量還會自動生成一個setter; 命名構(gòu)造函數(shù),使用命名構(gòu)造函數(shù)可以為一個類實現(xiàn)多個構(gòu)造函數(shù),也能更加清晰的表明你的意圖;

斷言是如果條件表達式不滿足則停止代碼執(zhí)行; 斷言只在檢查模式下運行有效,如果在生產(chǎn)模式下運行則不會執(zhí)行。

Dart 以兩種模式運行: Dart 1.x 有生產(chǎn)模式和檢查模式兩種模式, Dart 2.x 中移除了檢查模式。

注:建議在開發(fā)/測試模式中使用 檢查模式 運行 Dart VM ,因為它會添加警告和錯誤以幫助開發(fā)和調(diào)試過程;選中的模式會強制執(zhí)行各種檢查,例如類型檢查等。

dart標(biāo)識符可以包括字符和數(shù)字,但不能以 數(shù)字開頭 。

Dart 是一種面向?qū)ο蟮木幊陶Z言。

代碼說明:定義了一個類 TestClass ,這個類擁有一個方法 disp() ,方法可以實現(xiàn)在終端打印字符串 Hello Dart! ,使用 new 關(guān)鍵字創(chuàng)建類的對象,該對象調(diào)用方法 disp() 。

關(guān)于dart的學(xué)習(xí)還有很多;我列出如下: Flutter高級工程師進階學(xué)習(xí)資料;需要可以私信我。發(fā)送“核心筆記”或“手冊”,即可領(lǐng)取資料!

Flutter——pdf閱讀功能的實現(xiàn)

實現(xiàn)pdf閱讀、橫豎屏切換,以及pdf頁面的點擊放大和雙指放大等功能

在這個項目中使用的是 flutter_plugin_pdf_viewer: ^1.0.7 ,可以滿足我們最基本的pdf需求閱讀需求。所做的滿足項目需求的工作主要是橫豎屏切換功能,以及我們的初始化繼續(xù)閱讀等等。

首先導(dǎo)入插件部分源碼

插件所提供的示例,已經(jīng)滿足了最基本的圖片放大、橫屏閱讀的功能,我們工作的難點就在于pdf豎屏閱讀的實現(xiàn),所以我們需要解決的問題主要有以下幾點:

(1) 橫屏加載同一頁面不能重復(fù)流量加載

(2) 切換豎屏?xí)r加載速度不能過慢,頁面不能有斷層

(3) 橫豎屏切換時頁碼的定位保持

針對于上述問題,我們一一進行解決。

重復(fù)流量加載 ,解決這一問題比較簡單,我們可以利用緩存實現(xiàn),在每一次加載pdf頁時,存儲其(key,value),這樣在下一次加載時我們會判斷這個頁面在緩存中是否已經(jīng)存在,不存在重新加載,存在則調(diào)用緩存中的數(shù)據(jù),頁面銷毀時清除所有緩存即可。

切換橫豎屏 ,豎屏PDF閱讀的實現(xiàn),思路就是將所有橫屏頁面存在list中,使用LIstView.builder()進行繪制,這種方法存在的缺點就是太慢了,需要將所有頁面全部加載之后,才可以繪制頁面,用戶體驗非常差,所以我們需要做一些改進,為了提升加載速度,實現(xiàn)效果GIF中的效果,我們就要使用FutureBuilder()方法,來實現(xiàn)預(yù)加載功能,具體實現(xiàn)如下:

(在這里不對此組件過多介紹,后續(xù)會專門介紹此組件的使用),這樣我們就可以實現(xiàn)預(yù)加載的功能了。

橫豎屏切換定位 ,這個點的解決思路已經(jīng)在我的 (Flutter 初始化ListView定位子組件位置) 中進行了介紹,實現(xiàn)了解決。

至此,我們就解決了所有的難點問題。

本文標(biāo)題:Flutter手冊.pdf,flutter基礎(chǔ)教程
網(wǎng)站鏈接:http://muchs.cn/article10/phjcgo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作商城網(wǎng)站、網(wǎng)站建設(shè)、網(wǎng)站收錄靜態(tài)網(wǎng)站、外貿(mào)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)