欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

蘋(píng)果flutter源碼,flutter源代碼

Flutter 可滾動(dòng)組件 之 SingleChildScrollView (十五)

SingleChildScrollView 源碼定義如下:

萬(wàn)秀網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián)公司,萬(wàn)秀網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為萬(wàn)秀1000多家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站建設(shè)要多少錢(qián),請(qǐng)找那個(gè)售后服務(wù)好的萬(wàn)秀做網(wǎng)站的公司定做!

需要注意的是, 通常 SingleChildScrollView 只應(yīng)在期望的內(nèi)容不會(huì)超過(guò)屏幕太多時(shí)使用 ,這是因?yàn)?SingleChildScrollView 不支持基于 Sliver 的延遲加載模型,所以如果預(yù)計(jì)視口可能包含超出屏幕尺寸太多的內(nèi)容時(shí),那么使用 SingleChildScrollView 將會(huì)非常昂貴(性能差),此時(shí)應(yīng)該使用一些支持Sliver延遲加載的可滾動(dòng)組件,如 ListView 。

示例1

下面是一個(gè)將大寫(xiě)字母 A-Z 沿垂直方向顯示的例子,由于垂直方向空間會(huì)超過(guò)屏幕視口高度,所以我們使用SingleChildScrollView:

示例2

示例3 - 橫向滾動(dòng)

Flutter Dio源碼分析(四)--封裝

Flutter Dio源碼分析(一)--Dio介紹

Flutter Dio源碼分析(二)--HttpClient、Http、Dio對(duì)比

Flutter Dio源碼分析(三)--深度剖析

Flutter Dio源碼分析(四)--封裝

Flutter Dio源碼分析(一)--Dio介紹視頻教程

Flutter Dio源碼分析(二)--HttpClient、Http、Dio對(duì)比視頻教程

Flutter Dio源碼分析(三)--深度剖析視頻教程

Flutter Dio源碼分析(四)--封裝視頻教程

github倉(cāng)庫(kù)地址

本文會(huì)手把手教你該怎么去封裝一個(gè)類(lèi)庫(kù),平時(shí)在我們的工作中都是拿著別人的造好的輪子在使用,這篇文章將帶你怎么去自己造輪子,以后再碰到別的類(lèi)庫(kù)需要對(duì)其進(jìn)行封裝的時(shí)候提供一個(gè)的思路和方法。

在前面的文章中,我們對(duì) Dio 的基本使用、請(qǐng)求庫(kù)對(duì)比、源碼分析,我們知道 Dio 的使用非常的簡(jiǎn)單,那為什么還需要進(jìn)行封裝呢?有兩點(diǎn)如下:

當(dāng)組件庫(kù)方法發(fā)生重要改變需要遷移的時(shí)候如果有多處地方用到,那么需要對(duì)使用到的每個(gè)文件都進(jìn)行修改,非常的繁瑣而且很容易出問(wèn)題。

當(dāng)不需要 Dio 庫(kù)的時(shí)候,我們可以隨時(shí)方便切換到別的網(wǎng)絡(luò)請(qǐng)求庫(kù),當(dāng)然 Dio 目前內(nèi)置支持使用第三方庫(kù)的適配器。

因?yàn)橐粋€(gè)應(yīng)用程序基本都是統(tǒng)一的配置方式,所以我們可以針對(duì) 攔截器 、 轉(zhuǎn)換器 、 緩存 、 統(tǒng)一處理錯(cuò)誤 、 代理配置 、 證書(shū)校驗(yàn) 等多個(gè)配置進(jìn)行統(tǒng)一管理。

因?yàn)槲覀兊膽?yīng)用程序在每個(gè)頁(yè)面中都會(huì)用到網(wǎng)絡(luò)請(qǐng)求,那么如果我們每次請(qǐng)求的時(shí)候都去實(shí)例化一個(gè) Dio ,無(wú)非是增加了系統(tǒng)不必要的開(kāi)銷(xiāo),而使用單例模式對(duì)象一旦創(chuàng)建每次訪問(wèn)都是同一個(gè)對(duì)象,不需要再次實(shí)例化該類(lèi)的對(duì)象。

這是通過(guò)靜態(tài)變量的私有構(gòu)造器來(lái)創(chuàng)建的單例模式

我們對(duì) 超時(shí)時(shí)間 、 響應(yīng)時(shí)間 、 BaseUrl 進(jìn)行統(tǒng)一設(shè)置

因?yàn)椴还苁?get() 還是 post() 請(qǐng)求, Dio 內(nèi)部最終都會(huì)調(diào)用 request 方法,只是傳入的 method 不一樣,所以我們這里定義一個(gè)枚舉類(lèi)型在一個(gè)方法中進(jìn)行處理

我們已經(jīng)把 Restful API 風(fēng)格簡(jiǎn)化成了一個(gè)方法,通過(guò) DioMethod 來(lái)標(biāo)明不同的請(qǐng)求方式。在我們平時(shí)開(kāi)發(fā)的過(guò)程中,需要在請(qǐng)求前、響應(yīng)前、錯(cuò)誤時(shí)對(duì)某一些接口做特殊的處理,那我們就需要用到攔截器。 Dio 為我們提供了自定義攔截器功能,很容易輕松的實(shí)現(xiàn)對(duì)請(qǐng)求、響應(yīng)、錯(cuò)誤時(shí)進(jìn)行攔截

我們發(fā)現(xiàn)雖然 Dio 框架已經(jīng)封裝了一個(gè) DioError 類(lèi)庫(kù),但如果需要對(duì)返回的錯(cuò)誤進(jìn)行統(tǒng)一彈窗處理或者路由跳轉(zhuǎn)等就只能自定義了

在我們發(fā)送請(qǐng)求的時(shí)候會(huì)碰到幾種情況,比如需要對(duì)非open開(kāi)頭的接口自動(dòng)加上一些特定的參數(shù),獲取需要在請(qǐng)求頭增加統(tǒng)一的 token

在我們請(qǐng)求接口前可以對(duì)響應(yīng)數(shù)據(jù)進(jìn)行一些基礎(chǔ)的處理,比如對(duì)響應(yīng)的結(jié)果進(jìn)行自定義封裝,還可以針對(duì)單獨(dú)的 url 做特殊處理等。

我們看了轉(zhuǎn)換器的介紹,發(fā)現(xiàn)和攔截器的功能差不多,那為什么還要存在轉(zhuǎn)換器,有兩點(diǎn):

執(zhí)行流程: 請(qǐng)求攔截器 請(qǐng)求轉(zhuǎn)換器 發(fā)起請(qǐng)求 響應(yīng)轉(zhuǎn)換器 響應(yīng)攔截器 最終結(jié)果 。

只會(huì)被用于 'PUT'、 'POST'、 'PATCH'方法,因?yàn)橹挥羞@些方法才可以攜帶請(qǐng)求體(request body)

會(huì)被用于所有請(qǐng)求方法的返回?cái)?shù)據(jù)。

在開(kāi)發(fā)過(guò)程中,客戶端和服務(wù)器打交道的時(shí)候,往往會(huì)用一個(gè) token 來(lái)做校驗(yàn),因?yàn)槊總€(gè)公司處理刷新token的邏輯都不一樣,我這里舉一個(gè)簡(jiǎn)單的例子

為什么我們需要有取消請(qǐng)求的功能,如果當(dāng)我們的頁(yè)面在發(fā)送請(qǐng)求時(shí),用戶主動(dòng)退出當(dāng)前界面或者app應(yīng)用程序退出的時(shí)候數(shù)據(jù)還沒(méi)有響應(yīng),那我們就需要取消該網(wǎng)絡(luò)請(qǐng)求,防止不必要的錯(cuò)誤。

由 服務(wù)器生成 的 一小段文本信息 ,發(fā)送給瀏覽器,瀏覽器把 cookie 以kv形式保存到本地 某個(gè)目錄下的文本文件內(nèi),下一次請(qǐng)求同一網(wǎng)站時(shí)會(huì)把該 cookie 發(fā)送給服務(wù)器。

cookie 的使用需要用到兩個(gè)第三方組件 dio_cookie_manager 和 cookie_jar

因?yàn)樵谖覀兤綍r(shí)的開(kāi)發(fā)過(guò)程中,會(huì)碰到一種情況,在進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí),我們希望能正常訪問(wèn)到上次的數(shù)據(jù),對(duì)于用戶的體驗(yàn)比較好,而不是展示一個(gè)空白的頁(yè)面,該緩存主要是 《Flutter實(shí)戰(zhàn)》網(wǎng)絡(luò)接口緩存 提供參考。

我們?cè)诔绦蛲顺龊髢?nèi)存緩存將會(huì)消失,所以我們用 shared_preferences 進(jìn)行磁盤(pán)緩存數(shù)據(jù)。

在我們用flutter進(jìn)行抓包的時(shí)候需要配置 Dio 代理。由 DefaultHttpClientAdapter 提供了一個(gè) onHttpClientCreate 回調(diào)來(lái)設(shè)置底層 HttpClient 的代理。

用于驗(yàn)證正在訪問(wèn)的網(wǎng)站是否真實(shí)。提供安全性,因?yàn)樽C書(shū)和域名綁定,并且由根證書(shū)機(jī)構(gòu)簽名確認(rèn)。

日志打印主要是幫助我們開(kāi)發(fā)時(shí)進(jìn)行輔助排錯(cuò)

Flutter iOS 蘋(píng)果IAP(內(nèi)購(gòu))實(shí)現(xiàn)步驟及問(wèn)題總結(jié)(全網(wǎng)最全)

點(diǎn)擊 “協(xié)議、稅務(wù)和銀行業(yè)務(wù)”

內(nèi)購(gòu)用的是付費(fèi)應(yīng)用程序,先簽署《付費(fèi)應(yīng)用程序協(xié)議》,同意后狀態(tài)變更為“用戶信息待處理”,等待審核。

狀態(tài)更改完畢后,點(diǎn)擊“開(kāi)始設(shè)置稅務(wù)、銀行業(yè)務(wù)和聯(lián)系信息”。

(1)添加銀行賬戶,按照要求填寫(xiě)相關(guān)內(nèi)容即可。

(2)選擇報(bào)稅表,并填寫(xiě)。所有與 Apple 有商業(yè)合作者必選都是美國(guó),若有其他需求,可以多選。

繼續(xù)填寫(xiě),首先認(rèn)證公司基本信息,選擇所有人類(lèi)型,確認(rèn)無(wú)誤后認(rèn)證條款處打?qū)?/p>

Part I 部分,繼續(xù)核對(duì)公司相關(guān)信息,選填內(nèi)容可不填。

Part III 部分,簽署稅務(wù)條約,設(shè)置利益限制條款的種類(lèi),選填內(nèi)容可不填。此部分如果需要可勾選上下圖勾選框,不需要可不勾選,我們這個(gè)項(xiàng)目沒(méi)有用到part III 部分,所以沒(méi)有勾選。

Part XXX 部分,確認(rèn)之前填寫(xiě)的信息,勾選完畢后,提交

(3)填寫(xiě)聯(lián)系信息,共5個(gè)。高級(jí)管理、財(cái)務(wù)、技術(shù)、法務(wù)、營(yíng)銷(xiāo)。只需要提供5個(gè)人的基本信息即可。

只可使用一次的產(chǎn)品,使用之后即失效,必須再次購(gòu)買(mǎi)。

示例: 釣魚(yú) App 中的魚(yú)食。

只需購(gòu)買(mǎi)一次,不會(huì)過(guò)期或隨著使用而減少的產(chǎn)品。

示例: 游戲 App 的賽道。

允許用戶在固定時(shí)間段內(nèi)購(gòu)買(mǎi)動(dòng)態(tài)內(nèi)容的產(chǎn)品。除非用戶選擇取消,否則此類(lèi)訂閱會(huì)自動(dòng)續(xù)期。

示例: 每月訂閱提供流媒體服務(wù)的 App。

允許用戶購(gòu)買(mǎi)有時(shí)限性服務(wù)的產(chǎn)品。此 App 內(nèi)購(gòu)買(mǎi)項(xiàng)目的內(nèi)容可以是靜態(tài)的。此類(lèi)訂閱不會(huì)自動(dòng)續(xù)期。

示例: 為期一年的已歸檔文章目錄訂閱。

App 內(nèi)購(gòu)買(mǎi)項(xiàng)目的截屏,即所售項(xiàng)目的示意圖。例如,如果 App 內(nèi)購(gòu)買(mǎi)項(xiàng)目是一本圖書(shū),您可以提交圖書(shū)的截屏。您也可以提交購(gòu)買(mǎi)頁(yè)的截屏。該截屏僅用于 Apple 審核,不會(huì)在 App Store 中顯示。

截屏要求如下:

iOS 至少需要 640 x 920 像素

Apple tvOS 需要 1920 x 1080 像素

macOS 需要 1280 x 800 像素

App 審核圖像上傳后,可以替換,但無(wú)法移除。當(dāng)您的 App 內(nèi)購(gòu)買(mǎi)項(xiàng)目處于審核中時(shí),您無(wú)法更新截屏。

沙箱賬號(hào)是不能直接在App Store進(jìn)行登錄的,只能在點(diǎn)擊了購(gòu)買(mǎi)商品之后,在彈出的登錄框進(jìn)行登錄 。

驗(yàn)證是否已登錄沙箱測(cè)試賬號(hào):

設(shè)置--iTunes Store與App Store,頁(yè)面拉到最底部,會(huì)看到沙箱賬戶項(xiàng)會(huì)列出你已登錄的沙箱測(cè)試賬號(hào)!

操作方法一:打開(kāi)App Store應(yīng)用首頁(yè)滑到最下方--選中AppleID--注銷(xiāo)

操作方法二:設(shè)置--iTunes Store與App Store--選中AppleID--注銷(xiāo)

checks if the client can make payments(檢測(cè)App是否能支付)

getAvailablePurchases

Get all non-consumed purchases 獲取未消費(fèi)的商品

打印信息查詢(xún);

原因:

沒(méi)有先執(zhí)行g(shù)etProducts,直接執(zhí)行requestPurchase方法,要先拉取商品列表,再執(zhí)行購(gòu)買(mǎi)操作.

問(wèn)題描述;

1.漏單必須要處理,玩家花RMB購(gòu)買(mǎi)的東西卻丟失了,是絕對(duì)不能容忍的。所謂的漏單就是玩家已經(jīng)正常付費(fèi),卻沒(méi)有拿到該拿的道具。

解決:只要購(gòu)買(mǎi)成功,便將購(gòu)買(mǎi)記錄(receipt等賬單信息)保存下來(lái),然后將賬單信息傳送給我們游戲服務(wù)器,游戲服務(wù)器獲得賬單后,和蘋(píng)果服務(wù)器驗(yàn)證,賬單有效的話,回饋給游戲服務(wù)器處理,游戲服務(wù)器處理后,返回給游戲客戶端處理,處理完畢,將本地保存的購(gòu)買(mǎi)記錄刪除。

官方文檔:向蘋(píng)果校驗(yàn)支付憑證

21000 App Store無(wú)法讀取你提供的JSON數(shù)據(jù)

21002 收據(jù)數(shù)據(jù)不符合格式

21003 收據(jù)無(wú)法被驗(yàn)證

21004 你提供的共享密鑰和賬戶的共享密鑰不一致

21005 收據(jù)服務(wù)器當(dāng)前不可用

21006 收據(jù)是有效的,但訂閱服務(wù)已經(jīng)過(guò)期。當(dāng)收到這個(gè)信息時(shí),解碼后的收據(jù)信息也包含在返回內(nèi)容中

21007 收據(jù)信息是測(cè)試用(sandbox),但卻被發(fā)送到產(chǎn)品環(huán)境中驗(yàn)證 【請(qǐng)求sandbox校驗(yàn)支付憑證】

21008 收據(jù)信息是產(chǎn)品環(huán)境中使用,但卻被發(fā)送到測(cè)試環(huán)境中驗(yàn)證

消耗類(lèi)型: 例如:金幣、道具等。

非續(xù)訂訂閱: non-renewable subscription 例如:VIP

您的首個(gè) App 內(nèi)購(gòu)買(mǎi)項(xiàng)目必須以新的 App 版本提交。請(qǐng)創(chuàng)建您的 App 內(nèi)購(gòu)買(mǎi)項(xiàng)目,然后前往 App 的“App Store”頁(yè),從“App 內(nèi)購(gòu)買(mǎi)項(xiàng)目”中進(jìn)行選擇,點(diǎn)按“提交”。 了解更多

在上傳二進(jìn)制文件并提交首個(gè) App 內(nèi)購(gòu)買(mǎi)項(xiàng)目以供審核后,您可以使用下表提交其他 App 內(nèi)購(gòu)買(mǎi)項(xiàng)目。

唐巧-iOS應(yīng)用內(nèi)付費(fèi)(IAP)開(kāi)發(fā)步驟列表

未完~待續(xù)

當(dāng)使用內(nèi)購(gòu)購(gòu)買(mǎi)過(guò)商品之后沒(méi)有把這個(gè)交易關(guān)閉,所以再次去購(gòu)買(mǎi)商品后就會(huì)調(diào)用以前已經(jīng)購(gòu)買(mǎi)成功的交易去購(gòu)買(mǎi)因?yàn)橐呀?jīng)購(gòu)買(mǎi)過(guò),才會(huì)有這個(gè)提示

原因:添加內(nèi)購(gòu)項(xiàng)目時(shí),信息填寫(xiě)不完整,app審核圖像未上傳

處理方法:上傳app審核圖片( 合適的尺寸 ),點(diǎn)擊提交,狀態(tài)改為正在準(zhǔn)備審核中。

這個(gè)是內(nèi)購(gòu)選擇類(lèi)型不匹配原因?qū)е隆?/p>

購(gòu)買(mǎi)成功之后,Apple會(huì)返回以下四個(gè)數(shù)據(jù)給應(yīng)用

Reference

Review the updated Paid Applications Schedule.

游客身份解決方案:即不登錄也要能購(gòu)買(mǎi)

1)服務(wù)器端做一個(gè)蘋(píng)果審核機(jī)制,審核期間游客身份可以進(jìn)行一切行為,一旦審核通過(guò),修改服務(wù)端即可達(dá)到強(qiáng)制用戶登錄進(jìn)行內(nèi)購(gòu)買(mǎi)的目的(這個(gè)有點(diǎn)。。。)

2)游客可以進(jìn)行內(nèi)購(gòu)買(mǎi),購(gòu)買(mǎi)時(shí)以設(shè)備UUID為準(zhǔn),生成一個(gè)游客賬號(hào),將購(gòu)買(mǎi)信息保存在服務(wù)器和本地,當(dāng)用戶登錄正式賬戶后判斷此設(shè)備是否進(jìn)行過(guò)內(nèi)購(gòu),有的話提示用戶將游客身份購(gòu)買(mǎi)的權(quán)益與現(xiàn)有賬號(hào)綁定,如果綁定,游客權(quán)益則遷移到正式賬戶,如果不遷移,則游客身份和正是賬戶是兩個(gè)獨(dú)立賬戶,正式賬戶不享有游客身份的權(quán)益(我用的這個(gè))

內(nèi)購(gòu)游客模式解決方案

iOS內(nèi)購(gòu)規(guī)則

Flutter PDF閱讀,可顯示頁(yè)數(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)) {

//按下時(shí)的顏色

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return Colors.transparent;

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

//默認(rèn)狀態(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);

}

}

flutter源碼系列 PageView源碼分析以及監(jiān)聽(tīng)事件

最近一個(gè)項(xiàng)目要實(shí)現(xiàn)可以無(wú)限循環(huán)的PageView,主要思路是在初始化pageview的list的時(shí)候在開(kāi)始和結(jié)尾多加一個(gè)結(jié)尾和開(kāi)頭的widget,當(dāng)滑動(dòng)到開(kāi)頭和結(jié)尾的時(shí)候手動(dòng)進(jìn)行頁(yè)面的切換,詳細(xì)可以搜索pageview無(wú)限輪播。

這種方法有一個(gè)要點(diǎn)就是要維護(hù)兩個(gè)索引,一個(gè)是內(nèi)部list的索引,一個(gè)是外部顯示的索引,由于list的容量是比顯示的數(shù)量多2的,所以如果要在外部進(jìn)行一些比如指示器或者計(jì)時(shí)器功能要進(jìn)行和頁(yè)面同步顯示或者切換頁(yè)面操作時(shí),需要將顯示的索引轉(zhuǎn)換成list的索引。

不過(guò)網(wǎng)上說(shuō)的都是一些比較簡(jiǎn)單的實(shí)現(xiàn),看到比較多的就是當(dāng)滑動(dòng)到要手動(dòng)切換的時(shí)候進(jìn)行一個(gè)時(shí)延,這樣可以避免直接切換頁(yè)面造成的卡頓和跳動(dòng)現(xiàn)象。但是存在一個(gè)問(wèn)題,如果要同時(shí)實(shí)現(xiàn)一個(gè)跟隨頁(yè)面切換的指示器,就會(huì)出現(xiàn)當(dāng)頁(yè)面切換過(guò)去之后指示器才會(huì)跟著過(guò)去,因?yàn)轫?yè)面切換的時(shí)候執(zhí)行了時(shí)延,而時(shí)延之后才會(huì)真正改變索引,此時(shí)才會(huì)setstate,之后指示器才能響應(yīng)到索引的切換,但是如果在時(shí)延之前就切換的話又會(huì)出現(xiàn)指示器先行的情況。因此這種方法其實(shí)是存在一些問(wèn)題的。

所以解決這個(gè)問(wèn)題的關(guān)鍵在于如何進(jìn)行頁(yè)面切換的判斷。這里可以有兩種思路實(shí)現(xiàn),第一種是實(shí)現(xiàn)viewpage的onpagechanged方法,在里面進(jìn)行邏輯的判斷,然后用controller來(lái)進(jìn)行頁(yè)面跳轉(zhuǎn),不過(guò)這種方法存在當(dāng)controller跳轉(zhuǎn)的時(shí)候又會(huì)回調(diào)onpagechanged,所以就會(huì)出現(xiàn)多次對(duì)索引不必要操作,而且如果有比如計(jì)時(shí)器等額外的功能的話可能不方便將頁(yè)面邏輯分開(kāi),而且依舊無(wú)法解決指示器延遲問(wèn)題,同時(shí)也很難進(jìn)行細(xì)粒度的操作。

第二種方法我們就要去看pageview的源碼了,從源碼的角度來(lái)解決問(wèn)題才是正確的方法。首先我們點(diǎn)進(jìn)去pageview的源碼

看到這里其實(shí)已經(jīng)有一些思路了,我們之前難點(diǎn)在于重寫(xiě)了onpagechanged方法導(dǎo)致問(wèn)題無(wú)法很好的解決,現(xiàn)在我們找到了onpagechanged調(diào)用的地方,只要找辦法避免掉就可以實(shí)現(xiàn)了。

當(dāng)然這里我們要說(shuō)到NotificationListener,以及flutter對(duì)應(yīng)的冒泡事件傳輸機(jī)制,這里大家可以去看看這篇 文章 。

我來(lái)總結(jié)一下,其實(shí)就是flutter對(duì)于notification這個(gè)組件,有一中事件規(guī)則叫冒泡傳遞,底層的notification如果在它的 onNotification寫(xiě)的邏輯中返回是false以及它不是根結(jié)點(diǎn),就會(huì)去向上遍歷尋找它的祖先notification組件,知道遇到root節(jié)點(diǎn)或者某一個(gè)返回true,則事件傳遞結(jié)束。

而且在onNotification中可以對(duì)多種事件進(jìn)行監(jiān)聽(tīng)和處理,所以我們可以把對(duì)viewpage頁(yè)面跳轉(zhuǎn)對(duì)索引處理的邏輯寫(xiě)在這里,而且我們可以分別處理比如滑動(dòng)開(kāi)始的start事件和結(jié)束的end事件,分別進(jìn)行細(xì)粒度的邏輯的處理,這樣就可以在外部進(jìn)行操作和別的功能實(shí)現(xiàn)了。

因此不僅無(wú)限輪播事件可以通過(guò)這種方法來(lái)解決,如果有其他的操作也可以這樣進(jìn)行處理,而且因?yàn)槲覀儧](méi)有傳入onpagechanged方法,所以不存在多次調(diào)用的問(wèn)題,pageview那里判斷onpagechanged是null方法就不會(huì)進(jìn)去了,會(huì)直接我們寫(xiě)在pageview外面的notification的邏輯。

最后的結(jié)構(gòu)大概這樣

Flutter WebView加載本地html的問(wèn)題

最近項(xiàng)目中,用到了flutter中的webview加載帶有echarts控件的html文件,但是發(fā)現(xiàn)圖表一直無(wú)法顯示,通過(guò)查詢(xún)相關(guān)資料,分析apk包文件,知道了是由于flutter項(xiàng)目中的文件打包后的路徑發(fā)生變化,造成找不到相關(guān)依賴(lài),特此記錄一下,使用下面這個(gè)方法便可以解析出Android和IOS打包后的apk中資源文件的實(shí)際位置。

例如,你的資源文件是在flutter項(xiàng)目的根目錄下的 'assets/files/echart-pie.html',

那 'getAssetsPath('assets/files/echart-pie.html')'才是打包成apk后,資源文件的實(shí)際路徑。

按照上面的操作,你會(huì)發(fā)現(xiàn)在android設(shè)備上已經(jīng)可以正常顯示本地html頁(yè)面了,但是IOS設(shè)備上還是一臉懵逼;不要慌,這塊是由于webview_flutter本來(lái)就不支持加載本地文件,這時(shí)我們還需要修改下插件IOS部分的源碼,F(xiàn)lutterWebView.m文件:

通過(guò)以上騷操作,就可以實(shí)現(xiàn)webview_flutter在android和ios設(shè)備上加載本地html文件了。

最后:推薦一個(gè)插件,已經(jīng)在官方的基礎(chǔ)上進(jìn)行了優(yōu)化

webview_flutter_plus

網(wǎng)頁(yè)標(biāo)題:蘋(píng)果flutter源碼,flutter源代碼
本文路徑:http://chinadenli.net/article24/dsgjece.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT微信公眾號(hào)做網(wǎng)站外貿(mào)建站面包屑導(dǎo)航云服務(wù)器

廣告

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

成都seo排名網(wǎng)站優(yōu)化