在 Flutter 中,有各式各樣的按鈕,該怎麼選擇呢?就操作面上來說,就是按了會有反應的東西,就畫面設計上來說,最好的方式就是有圖有真相吧!因此〈Material Components widgets〉這類像是藝廊式的參考頁面,就是最方便的參考管道。
那麼這個主題就這樣了,可以結束了…XD
嗯…也不是這樣,來看一下 API 架構好了,以〈第一個 Flutter 專案〉中看過的 FloatingActionButton
來說,它直接繼承了 StatelessWidget
:
Widget > StatelessWidget > FloatingActionButton
然後,在介紹 Flutter 的按鈕元件相關文件上,常會出現的 FlatButton
、OutlineButton
、RaisedButton
,它們都是 MaterialButton
的子類別:
Widget > StatelessWidget > MaterialButton > FlatButton
Widget > StatelessWidget > MaterialButton > OutlineButton
Widget > StatelessWidget > MaterialButton > RaisedButton
如果你看一下它們的原始碼,這些按鈕元件的 build
傳回的 Widget
,都是 RawMaterialButton
,而它是 StatefulWidget
的子類別:
Widget > StatefulWidget > RawMaterialButton
其實如果你看過 FloatingActionButton
的原始碼,會發現它的 build
中,也會建立 RawMaterialButton
實例,build
傳回的 Widget
,子樹中會包含該實例。
RawMaterialButton
顧名思義,包含了許多「按鈕」的基本定義,除了 onPressed
、onLongPressed
事件特性之外,也包含了一些顏色設定、陰影、墨水動畫效果等,Flutter 中有許多按鈕,是基於 RawMaterialButton
來設計。
也就是說,如果 Flutter 本身提供的各式按鈕你都不滿意的話,也可以透過 RawMaterialButton
來自訂,例如,最常有人問的是,Text
能不能有 onPressed
事件?透過 RawMaterialButton
就可以!
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
body: Center(
child: TextButton('按我',
onPressed: () => print('被按了XD'),
)
)
),
)
);
class TextButton extends StatelessWidget {
final String text;
final VoidCallback onPressed;
TextButton(this.text, {this.onPressed});
@override
Widget build(BuildContext context) {
return RawMaterialButton(
child: Text(text),
onPressed: onPressed,
);
}
}
來看一下效果:
嗯?最後長按時那個效果是怎麼回事?那是 RawMaterialButton
內部使用了 InkWell
元件做出來的墨水渲染效果,可以藉由 splashColor
來改變顏色,如果想要讓上例中的文字更像個按鈕,可以如下:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
body: Center(
child: TextButton('按我',
onPressed: () => print('被按了XD'),
)
)
),
)
);
class TextButton extends StatelessWidget {
final String text;
final VoidCallback onPressed;
TextButton(this.text, {this.onPressed});
@override
Widget build(BuildContext context) {
return RawMaterialButton(
child: Text(text),
onPressed: onPressed,
fillColor: Colors.lightGreen,
splashColor: Colors.red,
);
}
}
執行時的效果會是:
方才談到,RawMaterialButton
包含了許多「按鈕」的基本定義,也就是傳統上你認知的…嗯…「按鈕」!如果你想做的是這類的按鈕,可以透過 RawMaterialButton
來自訂,只要它提供的效果你可以接受就好。
然而,也許你想做個沒有「按鈕」概念的按鈕,畢竟 Material Design 嘛!例如,想要有個 onPressed
事件就好,這可以透過 GestureDetector
來達到:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
body: Center(
child: TextButton('按我',
onPressed: () => print('被按了XD'),
)
)
),
)
);
class TextButton extends StatelessWidget {
final String text;
final VoidCallback onPressed;
TextButton(this.text, {this.onPressed});
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Text(text),
onTap: onPressed == null ? () => {} : onPressed,
);
}
}
這次就不會有顏色、陰影、動畫了:
不過呢!onPressed
其實也是「按鈕」概念下的東西,手機是平面吧!平面怎麼會有 onPressed
這種壓下的概念呢?最多也就是 click 之類的吧!也就是說,既然都用了 GestureDetector
,就用手勢上的事件定義就可以了,onPressed
的隱喻是有些多餘。
不過真要細談的話,GestureDetector
也是觸控事件(Pointer Event)的進一步封裝,這要談下去,會涉及事件處理的細節,之後專門談事件時再來說了。