將枚舉類型更改為常規(guī)類或將常規(guī)類更改為枚舉類型時,熱重載(r)不起作用。 需要hot restart(cmd + shift + r)
創(chuàng)新互聯(lián)建站科技有限公司專業(yè)互聯(lián)網(wǎng)基礎服務商,為您提供綿陽電信機房機柜租用,高防服務器,成都IDC機房托管,成都主機托管等互聯(lián)網(wǎng)服務。
修改泛型類型聲明后,熱重裝將無法工作。 例如,以下操作將無效:
Widget 快速替換 、 包裝 、 移動 、 刪除 、 抽取成變量 、 抽取成方法
焦點放到相應的widget上, 然后 cmd + . 如果提示沒有相關操作,多試幾次
Listener 它是主要的功能是用來監(jiān)聽屏幕觸摸事件,取決于它的子組件區(qū)域范圍,比如按下、移動、抬起、取消等操作時可以添加監(jiān)聽。
我們知道 Flutter 組件只有按鈕才會有事件,那么如果我需要在文字或者某個容器上添加事件那我就需要借助 Listener
手勢系列視頻教程地址
Listener 常用于當手指滑動屏幕時進行隱藏鍵盤或者下拉刷新、上拉加載時進行事件監(jiān)聽。
一般在實際的開發(fā)過程中我們很少會用到 Listener 來監(jiān)聽手勢,一般都是通過 GestureDetector 來進行監(jiān)聽或者使用 MouseRegion 來監(jiān)聽鼠標的事件,而 MouseRegion 常用于web開發(fā)中, GestureDetector 常用于app。
我們經(jīng)常使用的回調函數(shù)主要有三個
我們這里主要是針對 onPointerDown 、 onPointerMove 、 onPointerUp 進行演示,因為我們在平時的開發(fā)過程中最常用到的屬性就是這三個,而且其他的屬性也都被廢棄掉了。
我們這里先點擊橙色容器,在點擊一次紅色容器,他們打印的結果如下。
PointerEvent 是觸摸、手寫筆、鼠標事件的基類。
在上文中,我們知道了什么是 Listener 并寫了一個簡單的案例,在使用案例的過程中我們的事件里面都帶了一個 event 參數(shù),而所有的事件最終都是繼承自 PointerEvent ,那我們接下來看看 event 的參數(shù)有什么作用。
PointerEvent 的屬性非常多,但在我們實際的開發(fā)過程中很少會使用到,只有在特定的情景下才會使用對應的屬性。
如需要做一個全局懸浮的按鈕我們會使用到 position
如需要做繪圖軟件我們需要用到 buttons 、 kind 等
所以大家可以根據(jù)實際的應用場景來使用對應的屬性即可,下面是我對 PointerEvent 的屬性進行的一個詳細描述。
behavior 屬性,它決定子組件如何響應命中測試,它的值類型為 HitTestBehavior ,這是一個枚舉類,有三個枚舉值
對子組件一個接一個的進行命中測試,如果子組件中有測試通過的,則當前組件通過,這就意味著,如果指針事件作用于子組件上時,其父級組件也肯定可以收到該事件。
在命中測試時,將當前組件當成不透明處理(即使本身是透明的),最終的效果相當于當前Widget的整個區(qū)域都是點擊區(qū)域
點擊組件透明區(qū)域時,可以對自身邊界內及底部可視區(qū)域都進行命中測試,這意味著點擊頂部組件透明區(qū)域時,頂部組件和底部組件都可以接收到事件
我們這里演示每次都是先點擊綠色盒子在點擊文字,以便大家能更好的分辨出這三個屬性的使用區(qū)別
Listener 是 Flutter 中比較重要的功能性組件,它主要的功能是用來監(jiān)聽屏幕觸摸事件,事件回調可以獲取對應的屬性來個性化定制app功能。
與iOS的ViewController、Android的Activity一樣,F(xiàn)lutter中的Widget也存在生命周期,并且通過State來提現(xiàn)。而App則是一個特殊的Widget,除了需要處理視圖顯示的各個階段,還需要應對應用從啟動到退出所經(jīng)歷的各個狀態(tài)。
State的生命周期,指的是在用戶參與的情況查下,其關聯(lián)的Widget所經(jīng)歷的從創(chuàng)建到顯示再到更新最后到停止,直至銷毀的各個過程階段。
這些不同的階段涉及到的特定的任務處理,正確理解State的生命周期至關重要,State的生命周期流程圖圖,如下所示:
從圖中可以看到,State的生命周期可以分為3個階段:創(chuàng)建、更新、銷毀。下面將介紹每一個階段的具體流程
State初始化時會依次執(zhí)行:構造方法 - initState - didChangeDependencies - build,隨后完成頁面渲染
Widget的狀態(tài)更新,主要由3個方法觸發(fā):setState、didChangeDependencies與didUpdateWidget。
一旦這三個方法被調用,F(xiàn)lutter就回銷毀舊的Widget,并調用build方法重建Widget
組件銷毀相對比較簡單,組件被移除,或者頁面銷毀的時候,系統(tǒng)會調用deactivate和dispose這兩個方法來移除或銷毀組件
下面這張表格也可以幫助我們理解記憶這些調用實際
視圖的生命周期,定義了視圖的加載到構建的全過程,其回調機制能夠確保我們可以更具視圖的狀態(tài)選擇合適的時間做恰當?shù)氖虑?,而App的生命周期,則定義了App從啟動到退出的全過程
在原生Android、iOS開發(fā)中,有時我們需要再對應的App生命周期事件中做相應的處理,比如App從后臺進入前臺,從前臺退出后臺,或者在UI繪制完成后做一些處理。
這樣的需求,在原生開發(fā)中,可以通過重寫Activity、ViewController生命周期回調方法,或者是注冊應用程序的相關通知來兼容App的生命周期并做相應的處理。而在Flutter中,我們可以利用WidgetsBindingObserver類,來實現(xiàn)同樣的需求。
下面我們看看WidgetsBindingObserver中具體有哪些回調函數(shù):
didChangeAppLifecycleState回調函數(shù)中,有一個參數(shù)類型為AppLifecycleState的枚舉類型,這個枚舉類型是Flutter對App生命周期狀態(tài)的封裝,它的常用狀態(tài)包括:
可以將App切前后臺,控制臺輸出的App狀態(tài),可以發(fā)現(xiàn):
我們可以通過下面的這張圖直觀的了解狀態(tài)切換過程
除了需要監(jiān)聽App的生命周期回調做相應處理外,根據(jù)不同的需求,我們需要再組件宣講之后做一些與顯示安全相關的操作,在iOS中,可以通過GCD的方法,讓操作在下一個RunLoop執(zhí)行,在Android中,可以通過View.post()插入消息隊列,來保證在組件渲染后進行相關操作。在Flutter中實現(xiàn)同樣的需求會更簡單:使用WidgetsBinding來實現(xiàn)即可
WidgetsBinding提供了單詞Frame繪制回調和實時Frame繪制回調兩種機制來滿足不同的需求場景:
Row:在水平方向上排列子widget的列表。
Column:在垂直方向上排列子widget的列表。
注意:這兩個屬于多子節(jié)點空間,可以將children排列成一行/一列,但是自身不帶滾動屬性,如果超出了一行,在debug下面則會顯示溢出的提示。
MainAxisAlignment:主軸方向上的對齊方式,會對child的位置起作用,默認是start。
其中MainAxisAlignment枚舉值:
center:將children放置在主軸的中心;
end:將children放置在主軸的末尾;
spaceAround:將主軸方向上的空白區(qū)域均分,使得children之間的空白區(qū)域相等,但是首尾child的空白區(qū)域為1/2;
spaceBetween:將主軸方向上的空白區(qū)域均分,使得children之間的空白區(qū)域相等,首尾child都靠近首尾,沒有間隙;
spaceEvenly:將主軸方向上的空白區(qū)域均分,使得children之間的空白區(qū)域相等,包括首尾child;
start:將children放置在主軸的起點;
其中spaceAround、spaceBetween以及spaceEvenly的區(qū)別,就是對待首尾child的方式。其距離首尾的距離分別是空白區(qū)域的1/2、0、1。
MainAxisSize:在主軸方向占有空間的值,默認是max。
MainAxisSize的取值有兩種:
max:根據(jù)傳入的布局約束條件,最大化主軸方向的可用空間;
min:與max相反,是最小化主軸方向的可用空間;
CrossAxisAlignment:children在交叉軸方向的對齊方式,與MainAxisAlignment略有不同。
CrossAxisAlignment枚舉值有如下幾種:
baseline:在交叉軸方向,使得children的baseline對齊;
center:children在交叉軸上居中展示;
end:children在交叉軸上末尾展示;
start:children在交叉軸上起點處展示;
stretch:讓children填滿交叉軸方向;
TextDirection:阿拉伯語系的兼容設置,一般無需處理。
VerticalDirection:定義了children擺放順序,默認是down。
VerticalDirection枚舉值有兩種:
down:從top到bottom進行布局;
up:從bottom到top進行布局。
top對應Row以及Column的話,就是左邊和頂部,bottom的話,則是右邊和底部。
TextBaseline:使用的TextBaseline的方式,有兩種,前面已經(jīng)介紹過。
這個是Row/Column的內的小控件,可以用來實現(xiàn)權重的布局
這邊使用一個Container,里面是Row,使用Expanded對子節(jié)點進行權重處理,如果不使用Expanded,直接放入其他控件也是可以的,只是無法設置權重
對于內容過長的時候,會有溢出提示:
MainAxisAlignment.center:將children放置在主軸的中心;
MainAxisAlignment.start:將children放置在主軸的起點;
MainAxisAlignment.end:將children放置在主軸的末尾;
MainAxisAlignment.spaceAround:將主軸方向上的空白區(qū)域均分,使得children之間的空白區(qū)域相等,但是首尾child的空白區(qū)域為1/2;
MainAxisAlignment.spaceBetween:將主軸方向上的空白區(qū)域均分,使得children之間的空白區(qū)域相等,首尾child都靠近首尾,沒有間隙;
MainAxisAlignment.spaceEvenly:將主軸方向上的空白區(qū)域均分,使得children之間的空白區(qū)域相等,包括首尾child;
下一章我們學習基礎組件之Image
Flutter中自定義組件一般有兩種方式:
CustomPaint繼承自SingleChildRenderObjectWidget,即它可以在通過嵌套引入到widget樹中,并且可以有一個child子widget。它的構造方法如下:
painter和foregroundPainter需要接收CustomPainter對象,是CustomPaint核心。CustomPainter是進行UI繪制的核心類,繪制時, CustomPaint 首先在畫布上調用 painter繪制 , 然后再繪制它的 child Widget, child 繪制完成后再調用 foregroundPainter 進行繪制。
size屬性標識繪制區(qū)域大小,但當CustomPaint有child,該屬性將會忽略,而使用child的大小為繪制區(qū)域大小。
isComplex和willChange用于控制繪制層緩存處理的,這里暫不討論。
可實現(xiàn)CustomPainter子類進行UI繪制
實現(xiàn)paint方法進行真正的繪制,canvas是畫布對象,size是繪制區(qū)域,是從CustomPaint中size屬性傳遞得到的。繪制過程與Android原生開發(fā)十分類似,連API都十分相像,這點對熟悉Android原生開發(fā)者真是太友好了。
Paint對象是畫筆對象,就是繪圖工具,我們可以設置畫筆的顏色、粗細、是否抗鋸齒、筆觸形狀以及作畫風格等,通過這些屬性我們可以很方便的來定制自己的UI效果,在繪制的過程中可以定義多個畫筆,以便實現(xiàn)多種風格圖形的集合。
根據(jù)需求選擇合適的畫筆屬性,完成你的繪制。
Canvas是繪制的畫布,它包含了很多繪制方法,可以繪制出各種形狀的圖形。需要注意的是,畫布是應用所有控件都在使用的, 所以通過這個畫布其實是可以繪制充滿屏幕的內容的,每次繪制都應該限制在本控件的區(qū)域(Size)內, 以免繪制覆蓋到其他組件。
下面介紹下Canvas的繪制方法:
PointMode是個枚舉
p1、p2為線段兩個端點
Rect定義矩形的大小位置,有多種構造方式:
RRect描述圓角矩形,他通過Rect和Radius來構造
畫圓比較簡單,c表示圓心位置,radius是半徑。
橢圓使用外接矩形確定大小位置,rect就是外接矩形。
繪制弧形,先確定弧形對應的橢圓,同樣地用外接矩形rect確定橢圓,然后根據(jù)起始點和結束點角度來確定那一段弧度,startAngle,sweepAngle分別代表起始和結束點角度,角度用弧度表示法。
useCenter表示是否連接閉合形狀,userCenter = false表示不閉合,即畫一段弧線,userCenter = true表示閉合,即繪制一個扇形。
繪制路徑,關鍵在于構建路徑Path,可以直接new Path對象,然后通過path方法可以連接出圖形,path關鍵方法如下:
還有其他方法,有興趣可以查看API。