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。默认为falseDecoration? 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),
),