來吧!Flutter(13) — Animated Dialog
上一篇文章我們討論了 DatePicker、DateRangePicker 以及 TimePicker,Flutter 提供了方便的方法可以呼叫這三個 Picker:showDatePicker、showDateRangePicker、showTimePicker。查看源碼發現,其實這三個方法都是包裝 showDialog 來將該 Picker 以 Dialog 的形式跳出,而不需要切換至新的頁面。
本篇文章,我們自己定義一個 Dialog,並且使用 showDialog 呼叫出來。
showDialog
首先,看一下 showDialog 的建構子。
在 showDialog 方法中,包含下列引數:
- BuildContext context:用來取得 App 的 全域參數,以及用來建立 Dialog,
- widgetBuilder builder:用來建立顯示的 Widget。
- bool barrierDismissible:是否可以點 Dialog 的外圍來關閉,預設為 true。
- Color barrierColor:Dialog 的外圍背景顏色。
- bool useSafeArea:是否使用 SafeArea,預設為 true。
- bool useRootNavigator:是否要 Navigator.push 離 context 最近或是最遠的對話框,預設是 true。
使用 showDialog 顯示一個 Dialog,必要傳入的引數是 context、builder。
假設我們有一個 Widget,名稱為 MyDialog,
那麼,我們就可以直接使用 showDialog 來顯示。
showDialog(
context,
builder:(_)=> MyDialog()
);
完整範例:
調整一下 Dialog 介面:
下一步?
前面我們介紹,利用 showDialog 可以把 widget 以 Dialog 的形式顯示,呼叫 showDialog 之後,Widget 立刻就會顯示。
接下來,我們把 Dialog 的出現加上一些過場效果。
動畫原理:
要讓 Dialog 會動,我們需要先了解動畫的原理。
前面我們已經設定一個 Dialog 的 Widget ,其位置是在畫面的正中間,其大小為 Screen 的 寬度的二分之一。
要讓 Dialog 由底下出現,表示它的位置是由 Screen 的下方外側移動到正中間。
Transform class
Flutter 提供 Transform class 可以修改 Widget 的大小、位置、形狀…
把要轉換的 Widget 傳入 child 引數,將轉換的方式傳入 tranform 引數中,這邊 transform 是 Matrix4 類型。
Matrix4.translationValues
- Matrix4 提供 translationValues(double x, double y ,double z),可以將帶入的 widget 根據傳給 translationValue 的值改變其位置。其中,橫向:X,縱向:Y,深度:Z。
- 我們這次的目標需要將對話框由畫面的最下方的外側移動到原本的位置,所以我們可以只設定 translationValues 的 y 即可。
- 畫面的高度可以使用 MediaQuery.of(context).size.heigh 取得,因為我們已經將 Widget 放在正中間,所以剩餘可以移動的位置就是 MediaQuery.of(context).size.heigh/2。
- 別忘了 Widget 設定的高度,因為是放在正中間,所以在中心點以下的高度只有原本設定的一半,所以我們 Transform 的值就會是由
MediaQuery.of(context).size.height / 2 +MediaQuery.of(context).size.width / 2 → 0.0Matrix4.translationValues(
0.0,
MediaQuery.of(context).size.height / 2 +
MediaQuery.of(context).size.width / 2,
0.0)->Matrix4.translationValues(
0.0,
0.0,
0.0)
那麼,要怎麼動態設定 translationValues 的 y 值呢?
我們發現,這邊只有改變一個 double 值,我們可以使用 Tween<T extends dynamic> class 根據我們設定起始值及終值,接者設定改變的方式,Tween class 就會根據我們的設定值,將起始值與終值中間的的值補足。
- 我們只需要產生一連串的 double 值,其值的區間為 1.0 至 0.0。
var _tweenValue = Tween<double>(begin: 1.0, end: 0.0);
上面設定一個補間的值,起始值為 1.0,終值為 0.0。
接者,我們設定補間的時間與方式。
CurvedAnimated
- parent:AnimationController,動畫的時間…。
- curve:變化曲線。
CurvedAnimation 帶入 AnimationController 以及 Curve。
其中,AnimationController 中的 vsync 需帶入TickerProvider ,這邊我們帶入 this,因為我們將此 widget 增加了 SingleTickerProviderStateMixin;duration 為 500 ms。
我們將 _animation 帶入 Tween 中
接者將 _tween.value 跟 Transform.translationValues 結合在一起。
Tween 會由 1.0 降至 0.0 ,所以 Transform 的 transform 每次都會取得不同的 y 值,進而把 widget 畫在不同的地方。
最後,也是最重要的一點,Flutter 的 widget 不會頻繁的更新,只有當呼叫 setState 的時候才會重新繪製,所以我們需要在每次 AnimationController 更新的時候呼叫 setState,如此 widget 才會在每次 AnimationController 更新時,都會重新以新的 Tween 值繪製。
完整程式碼如下:
小記
動畫是 Flutter 主打的項目之一,我們這次把 Dialog 的出現加上動畫的效果,讓整個對話框的出現更有動態感。
動畫的設置看似很複雜,把每一個步驟細分就可以很輕鬆的把動畫設置完成。
如果這篇文章有幫助到你,可以拍手鼓勵鼓勵我。
謝謝
參考
showDialog: https://api.flutter.dev/flutter/material/showDialog.html
Transform Class: https://api.flutter.dev/flutter/widgets/Transform-class.html
Tween Class:https://api.flutter.dev/flutter/animation/Tween-class.html
Curved Animation Class:https://api.flutter.dev/flutter/animation/CurvedAnimation-class.html
AnimationController:https://api.flutter.dev/flutter/animation/AnimationController-class.html