国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Flutter交互實戰-即刻App探索頁下拉&拖拽效果

miracledan / 3262人閱讀

摘要:前言最近比較熱門,但是成體系的文章并不多,前期避免不了踩坑我這篇文章主要介紹如何使用實現一個比較復雜的手勢交互,順便分享一下我在使用過程中遇到的一些小坑,減少大家入坑作者鏈接先睹為快本項目支持運行,效果如下對了,順便分享一下生成的小竅門,建

前言

Flutter最近比較熱門,但是Flutter成體系的文章并不多,前期避免不了踩坑;我這篇文章主要介紹如何使用Flutter實現一個比較復雜的手勢交互,順便分享一下我在使用Flutter過程中遇到的一些小坑,減少大家入坑;

作者:HitenDev
鏈接:https://www.jianshu.com/p/4d1...

先睹為快

本項目支持ios&android運行,效果如下

對了,順便分享一下生成gif的小竅門,建議用手機自帶錄屏功能導出mp4文件到電腦,然后電腦端用ffmpeg命令行處理,控制gif的質量和文件大小,我的建議是分辨率控制在270p,幀率在10左右;

交互分析

看文章的小伙伴最好能手持即刻App),親自體驗一下探索頁的交互,是黃色Logo黃色主題色的即刻;有人稱‘黃即’;

即刻App原版功能有卡片旋轉,卡片撤回和卡片自動移除,時間關系暫時沒有實現,但核心的功能都在;

從一個Android開發者的習慣來看待,這個交互可拆分內外兩層控件,外層我們需要一個整體下拉的控件,我稱為下拉控件;內層我們需要實現一個上、下、左、右四方向拖拽移動的控件,我們稱為卡片控件下拉控件卡片控件不僅要處理手勢,還需要處理子Widget的布局;下面我再分析細節功能:

下拉控件:

子控件從上到下豎直擺放,頂部菜單默認隱藏在屏幕外

下拉手勢所有子控件下移,菜單視覺差效果

支持點擊自動展開、收起效果

卡片控件

卡片層疊布局,錯落有致

最上層卡片支持手勢拖拽

其他卡片相應拖拽小幅位移

松手移除卡片

碼上入手 熱身

套用App開發伎倆,實現上面的交互無非就是控件布局和手勢識別。當然Flutter開發也是這些套路,只不過萬物皆是Widget,在Flutter中常用的基本布局有ColumnRowStack等,手勢識別有ListenerGestureDetectorRawGestureDetector等,這是本文重點講解的控件,不限于上面這幾個Widget,因為Flutter提供的Widget太多了,重點的控件需要牢記外,其他時候真是現用現查;

所以下面我們從布局和手勢這兩個大的技術點,來一一擊破功能點;

布局擺放

這里所謂的布局,包括Widget的尺寸大小和位置的控制,一般都是父Widget掌管子Widget的命運,Flutter就是一層一層Widget嵌套,不要擔心,下面從外到內具體案例講解;

下拉控件

首先我們要實現最外層布局,效果是:子Widget豎直擺放,且最上面的Widget默認需要擺放在屏幕外;

如上圖所示,紅色區域是屏幕范圍,header是頭部隱藏的菜單布局,content是卡片布局的主體;

先說入的坑

豎直布局我最先想到的是Column,我想要的效果是content高度和父Widget的高度一致,我首先想到是讓Expanded包裹content,結果是content的高度永遠等于Column高度減header高度,造成現象就是content高度不填充,或者是擠壓現象,如果繼續使用Colunm可能就得放棄Expanded,手動給content賦值高度,沒準是個辦法,但我不愿意手動賦值content的高度,太不優雅了,最后果斷棄用Column

另一個問題是如何隱藏header,我想到兩種方案:

采用外層Transform包裹整個布局,內層Transform包裹header,然后賦值內層dy = -headerHeight,隨著手勢下拉動態,并不改變headerTransform,而是改變最外層Transformdy

動態改變header高度,初始高度為0,隨著手勢下拉動態計算;

但是上面這兩種都有坑,第一種方式會影響控件的點擊事件,onTap方法不會被回調;第二種由于高度在不斷改變,會影響header內部子Widget的布局,很難做視覺差的控制;

最終方案

最后采用Stack來布局,通過Stack配合Positioned,實現header布局在屏幕外,而且可以做到讓content布局填充父Widget;

PullDragWidget

首先解釋一下Positioned的基本用法,topbottomheight控制高度和位置,而且兩兩配合使用,topbottom可以理解成marginTop和marginBottom,height顧名思義是直接Widget的高度,如果top配置bottom,意味著高度等于parentHeight-top-bottom,如果top/bottom配合height使用,高度一般是固定的,當然topbottom是接受負數的;

再分析代碼,首先_offsetY是下拉距離,是一個改變的量初始值為0,content需要設置top = _offsetYbottom = -_offsetY,改變的是上下位置,高度不會改變;同理,header是采用topheight控制,高度固定,只需要動態改變top即可;

用Flutter寫布局真的很簡單,我極力推崇使用Stack布局,因為它比較靈活,沒有太多的限制,用好Stack主要還得用好Positioned,學好它沒錯;

卡片控件

卡片實現的效果就是依次層疊,錯落有致,這個很容易想到Stack來實現,當然有了上面踩坑,用Stack算是很輕松了;

重疊的效果使用Stack很簡單,錯落有致的效果實在起來可能性就比較多了,比如可以使用Positioned,也可以包裹Container改變margin或者padding,但是考慮到角度的旋轉,我選擇使用Transform,因為Transform不僅可以玩轉位移,還有角度和縮放等,其內部實際上是操作一個矩陣變換;Transform挺好用,但是在Transform多層嵌套的某些特殊情況下,會存在不響應onTap事件的情況,我想這應該是Transform的bug,拖拽事件暫時沒有發現問題,這個是不是bug有待確認,暫時不影響使用;

CardStackWidget

_CardWidget

簡單總結一下卡片布局代碼,CardStackWidget是管理卡片Stack的父控件,負責對每個卡片進行布局,_CardWidget是對多帶帶卡片內部進行布局,總體來說沒有什么難點,細節控制邏輯是在對上層_CardWidget和底層_CardWidget偏移量的計算;

布局的內容就講這么多,整體來說還是比較簡單,所謂的有些坑也不一定算是坑,只是不適應某些應用場景罷了;

手勢識別

Flutter手勢識別最常用的是ListenerGestureDetector這兩個Widget,其中Listener主要針對原始觸摸點進行處理,GestureDetector已經對原始觸摸點加工成了不同的手勢;這兩個類的方法介紹如下;

Listener

GestureDetector手勢回調:

ListenerGestureDetector如何抉擇,首先GestureDetector是基于Listener封裝,它解決了大部分手勢沖突,我們使用GestureDetector就夠用了,但是GestureDetector不是萬能的,必要時候需要自定義RawGestureDetector

另外一個很重要的概念,Flutter手勢事件是一個從內Widget向外Widget的冒泡機制,假設內外Widget同時監聽豎直方向的拖拽事件onVerticalDragUpdate,往往都是內層控件獲得事件,外層事件被動取消;這樣的概念和Android父布局攔截機制就完全不同了;

雖然Flutter沒有外層攔截機制,但是似乎還有一線希望,那就是IgnorePointerAbsorbPointerWidget,這倆哥們可以忽略或者阻止子Widget樹不響應Event;

手勢分析

基本原理介紹完了,接下來分析案例交互,上面說了我把整體布局拆分成了下拉控件和卡片控件,分析即刻App的拖拽的行為:當下拉控件沒有展開下拉菜單時,卡片控件是可以相應上、左、右三個方向的手勢,下拉控件只相應一個向下方向的手勢;當下拉菜單展開時,卡片不能相應任何手勢,下拉控件可以相應豎直方向的所有事件;

上圖更加形象解釋兩種狀態下的手勢響應,下拉控件是父Widget,卡片控件是子Widget,由于子Widget能優先響手勢,所以在初始階段,我們不能讓子Widget響應向下的手勢;

由于GestureDetector只封裝水平和豎直方向的手勢,且兩種手勢不能同時使用,我們從GestureDetector源碼來看,能不能封裝一個監聽不同四個方向的手勢,;

GestureDetector

GestureDetector最終返回的是RawGestureDetector,其中gestures是一個map,豎直方向的手勢在VerticalDragGestureRecognizer這個類;

VerticalDragGestureRecognizer

VerticalDragGestureRecognizer繼承DragGestureRecognizer,大部分邏輯都在DragGestureRecognizer中,我們只關注重寫的方法:

_hasSufficientPendingDragDeltaToAccept方法是關鍵邏輯,控制是否接受該拖拽手勢

_getDeltaForDetails返回拖拽進度的dx、dy偏移量

_getPrimaryValueFromOffset返回單方向手勢value,不同方向(同時擁有水平和豎直)的可以傳null

_isFlingGesture是否該手勢的Fling行為

自定義DragGestureRecognizer

想實現接受三個方向的手勢,自定義DragGestureRecognizer是一個好的思路;我希望接受上、下、左、右四個方向的參數,根據參數不同監聽不同的手勢行為,照葫蘆畫瓢自定義一個接受方向的GestureRecognizer

DirectionGestureRecognizer

可參考原Demo

由于DragGestureRecognizer的很多方法是私有的,想重新只能copy一份代碼出來,然后重寫主要的方法,根據不同入參處理不同的手勢邏輯;

注意事項

敲黑板了,在自定義DragGestureRecognizer時:_getDeltaForDetails返回值表示dxdy的偏移量,在只存在水平或者只存在豎直方向的情況下,需要將另一個方向的dxdy置0;

當前Widget樹有且只存在一個手勢時,手勢判斷的邏輯_hasSufficientPendingDragDeltaToAccept可能不會被調用,這時候一定要重寫_getDeltaForDetails控制返回dxdy

如何使用

自定義的DirectionGestureRecognizer可以配置leftrightupdown四個方向的手勢,而且支持不同方向的組合;

比如我們只想監聽豎直向下方向,就創建DirectionGestureRecognizer(DirectionGestureRecognizer.down)的手勢識別;

想監聽上、左、右的手勢,創建DirectionGestureRecognizer(DirectionGestureRecognizer.left | DirectionGestureRecognizer.right | DirectionGestureRecognizer.up)的手勢識別;

DirectionGestureRecognizer就像一把磨刀石,刀已經磨鋒利,砍材就很輕松了,下面進行控件的手勢實現;

下拉控件手勢

PullDragWidget

PullDragWidget是下拉拖拽控件,根Widget是一個RawGestureDetector用來監聽手勢,其中gestures支持向下拖拽和點擊兩個手勢;當下拉控件處于_opened狀態說header已經拉下來,此時配合IgnorePointer,禁用子Widget所有的事件監聽,自然內部的卡片就相應不了任何事件;

卡片控件手勢

同下拉控件一樣,卡片控件只需要監聽其余三個方向的手勢,即可完成任務:

CardStackWidget

手勢答疑

為什么不用 onPanDown onPanUpdate onPanEnd 來拖動?

這是掘金評論提的問題,我解答一下:在GestureDetector中有Pan手勢和Drag手勢,這兩個手勢都能用處拖拽的場景,但不同的是Drag手勢僅限于水平豎直方向的監聽,Pan手勢不約束方向任意方向都能監聽,除此之外觸發條件也不一致,Pan手勢的觸發條件是滑動動屏幕的距離distance大于kTouchSlop*2Drag手勢的觸發條件是dx或者dy大于kTouchSlopdxdydistance形成勾股定理的三個邊長;假設同樣在監聽豎直滑動這種場景,VerticalDrag總是比Pan先觸發;如果下拉控件用VerticalDrag卡片控件用Pan,下拉控件會優先獲取向上的拖拽,卡片控件就會失去向上拖拽的機會,這就實現不了交互了,退一步即使Pan的觸發條件跟VerticalDrag一樣,由于Flutter的事件傳遞是從內到外的,這會導致外層下拉控件完全失去響應機會。以上我的個人理解,如有誤導還請大佬評論指正。

手勢小結

分析Flutter手勢冒泡的特性,父Widget既沒有響應事件的優先權,也沒有監聽多帶帶方向(leftrightupdown)的手勢,只能自己想辦法自定義GestureRecognizer,把原本VerticalHorizontal兩個方向的手勢識別擴展成leftrightupdown四個方向,區分開會產生沖突的手勢;

當然也可能有其他的方案來實現該交互的手勢識別,條條大路通羅馬,我只是拋磚引玉,大家有好的方案可以積極留言提出寶貴意見;

總結

知識點

由于篇幅有限并沒有介紹完該交互的所有內容,深表遺憾,總結歸納一下代碼中用到的知識點:

ColumnRowExpandedStackPositionedTransform等Widget的使用;

GestureDetectorRawGestureDetectorIgnorePointer等Widget的使用;

自定義GestureRecognizer實現自定義手勢識別;

AnimationControllerTween等動畫的使用;

EventBus的使用;

最后

上面章節主要介紹在當前場景下用Flutter布局和手勢的實戰技巧,其中更深層次手勢競技和分發的源碼級分析,有機會再做深入學習和分享;

另外本篇并不是循序漸進的零基礎入門,對剛接觸的同學可能感覺有點懵,但是沒有關系,建議你clone一份代碼跑起來效果,沒準就能提起自己學習的興趣;

最最后,本篇所有代碼都是開源的,你的點贊是對我最大的鼓勵。

項目地址:
https://github.com/HitenDev/F...
閱讀更多

一波Flutter酷炫特效來襲

金三銀四,2019最新面試實戰總結

從來不糾結算法,冒泡排序這樣優化?

動畫:一招學會TCP的三次握手和四次揮手

關于Gradle, 搞定Groovy閉包這一篇就夠了

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/54982.html

相關文章

  • Flutter交互實戰即刻App探索下拉拖拽效果

    摘要:前言最近比較熱門,但是成體系的文章并不多,前期避免不了踩坑我這篇文章主要介紹如何使用實現一個比較復雜的手勢交互,順便分享一下我在使用過程中遇到的一些小坑,減少大家入坑作者鏈接先睹為快本項目支持運行,效果如下對了,順便分享一下生成的小竅門,建 前言 Flutter最近比較熱門,但是Flutter成體系的文章并不多,前期避免不了踩坑;我這篇文章主要介紹如何使用Flutter實現一個比較復雜...

    wdzgege 評論0 收藏0
  • 5 月編程語言排行榜:Java第一,R跌出Top20

    摘要:我們都知道,最近,發布了月份編程語言排行榜。其中,前三名依然健穩不變,他們分別是,第四則為,第五則為。這樣比較一下,發現確實會長期是編程語言的第一名。很多人看好的語言,卻仍在左右徘徊。 我們都知道,最近,TIOBE 發布了 5 月份編程語言排行榜。其中,前三名依然健穩不變,他們分別是 Java、C、C++,第四則為: Python ,第五則為 VB .NET。 下面兩張圖,我們可以看到...

    GT 評論0 收藏0
  • 憑什么看不起外包員工?外包還值得進嗎?

    摘要:所以就找外包公司,找到一個有經驗的程序員來做,這樣做既可以保證質量,有可以跟上進度。為什么不建議去外包為什么不要去外包公司總體原因如下沒有歸屬感想想工作周圍大部分不是自己的同事,想找人說個話都難。 前言 最近有好多人討論外包,前幾天看到一個帖子說就是有一個外包吃了公司的的零食,遭到HR當場批評, 搞的整個IT界備受關注,那么外包公司和非外包公司有什么樣的不一樣呢?我今天也說說我的看法! ...

    lei___ 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<