Flutter自定義Tooltip
在以前,對Tooltip元件的唯一印象就是白加黑,如下圖所示
後來發現電腦端的軟體,Tooltip都是各種樣式。我正好也要用到這種可以自定義Tooltip的功能,本來想要不用MouseRegion元件和Overlay元件寫一個。想了一下,有點過於繁瑣,於是就去pub.dev找了一圈,看有沒有已經造好的輪子,可惜沒找到。
要不還是先試試Tooltip吧,想著看了一下這個元件的屬性,立馬像發現了新大陸。這些功能原來Tooptip早就已經具有了。
Tooltip
該元件一共具有以下多個屬性:
-
String? message
:提示的文字資訊 -
InlineSpan? richMessage
:提示的自定義資訊 -
double? height
:提示的高度 -
EdgeInsetsGeometry? padding
:提示的內邊距 -
EdgeInsetsGeometry? margin
:提示的外邊距 -
double? verticalOffset
:提示顯示的垂直偏移 -
bool? preferBelow
:工具提示是否預設顯示在小部件下方。預設為true。如果沒有足夠的空間以首選方向顯示工具提示,則工具提示將向相反方向顯示 -
bool? excludeFromSemantics
:如果Tooltip元件為Semantics的子元件,側設定為true。預設為false -
Decoration? decoration
-
TextStyle? textStyle
:提示顯示的文字樣式 -
Duration? waitDuration
:滑鼠懸停多久才顯示提示 -
Duration? showDuration
:提示顯示持續的時間 -
Widget? child
:提示應用的子元素 -
TooltipTriggerMode? triggerMode
:提示觸達的模式(條件)。僅在移動端適用 -
bool? enableFeedback
:是否應提供聲音和/或觸覺反饋。在 Android 上,當啟用反饋時,點選會產生點選聲,長按會產生短暫的振動
預設的Tooltip有點醜,我們來把它修改得漂亮一點
Tooltip( message: '海綿寶寶', padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Colors.white, borderRadius: const BorderRadius.all(Radius.circular(4)), boxShadow: [ BoxShadow(blurRadius: 2, color: Colors.black.withOpacity(.2)) ], ), textStyle: const TextStyle(color: Colors.black), child: Image.asset('assets/images/hmbb.png', width: 250), )
預設Tooltip一放上去就顯示,一離開就消失,我們來自定義顯示和消失的時間
Tooltip(
...
waitDuration: const Duration(seconds: 2),
showDuration: const Duration(seconds: 2),
)
預設提示顯示的最大寬度為程式的最大寬度,當提示顯示的資訊更多,就會變成如下樣子
Tooltip(
message: '海綿寶寶' * 10,
...
)
Tooltip只有一個設定高度的值,沒有設定寬度的值。那我們要是想多行顯示資訊怎麼辦?最簡單的就是以下這樣書寫
Tooltip(
message: '姓名:海綿寶寶\n職務:蟹堡王餐廳大廚',
...
)
當然,也可以這樣寫
Tooltip(
message: '''
姓名:海綿寶寶
職務:蟹堡王餐廳大廚''',
...
)
效果一樣,但是不好動態獲取提示資訊。最好的解決方案就是使用richMessage屬性。
richMessage
該屬性傳遞一個InlineSpan物件,所以我們可以在提示中為所欲為,顯示任何內容。
假入我們有以下資訊需要顯示
Role role = Role(name: '海綿寶寶', city: '比奇堡', age: 36, position: '蟹堡王餐廳的高階廚師');
我們可以使用以下程式碼
Tooltip(
richMessage: WidgetSpan(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('姓名:${role.name}'),
Text('地址:${role.city}'),
Text('年齡:${role.age}'),
Text('職位:${role.position}'),
],
),
),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(4)),
boxShadow: [
BoxShadow(blurRadius: 2, color: Colors.black.withOpacity(.2))
],
),
child: Image.asset('assets/images/hmbb.png', width: 250),
),
顯示是能顯示了,但是這個位置把海綿寶寶給擋住了,我們來更改一下它的位置。我們要是想讓提示顯示在圖片下面,只要把垂直方向向下移動子元素的高度一半距離
Tooltip(
// 817和806是原圖大小,250是設定顯示的寬度, 817 * 250 / 806計算當前高度
verticalOffset: 817 * 250 / 806 / 2,
...
)
Tooltip中只有一個設定垂直距離的屬性,那要是我們想讓它右邊或左邊顯示怎麼辦?我們可以使用margin這個屬性
Tooltip(
margin: const EdgeInsets.only(left: 250),
...
)
提示雖然顯示到右邊去了,但是還是會遮住圖片(這裡背景是透明,所以不太能看出效果)。我們怎麼才能讓它顯示在圖片外的最右邊呢?把margin值寫大一點當然可行,我們這裡可以計算的精準一點。
要想計算好位置,我們需要知道兩個值。提示顯示的寬度和圖片的寬度。圖片的寬度我們設定成了250,提示的寬度是動態的,我們不好知道,所以我們可以用一個固定寬度包住它
Tooltip(
richMessage: WidgetSpan(
child: SizedBox(
width: 200,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('姓名:${role.name}'),
Text('地址:${role.city}'),
Text('年齡:${role.age}'),
Text('職位:${role.position}'),
],
),
),
),
...
),
然後通過以下算式計算
Tooltip(
...
// 250為圖片的寬度,200為提示的寬度
margin: const EdgeInsets.only(left: 250 * 2 - (250 - 200) / 2),
),