Flutter自定义Tooltip

在以前,对Tooltip组件的唯一印象就是白加黑,如下图所示

image

后来发现电脑端的软件,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),
)
复制代码

image

默认Tooltip一放上去就显示,一离开就消失,我们来自定义显示和消失的时间

Tooltip(
  ...
  waitDuration: const Duration(seconds: 2),
  showDuration: const Duration(seconds: 2),
)
复制代码

image

默认提示显示的最大宽度为程序的最大宽度,当提示显示的信息更多,就会变成如下样子

Tooltip(
  message: '海绵宝宝' * 10,
  ...
)
复制代码

image

Tooltip只有一个设置高度的值,没有设置宽度的值。那我们要是想多行显示信息怎么办?最简单的就是以下这样书写

Tooltip(
  message: '姓名:海绵宝宝\n职务:蟹堡王餐厅大厨',
  ...
)
复制代码

image

当然,也可以这样写

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),
),
复制代码

image

显示是能显示了,但是这个位置把海绵宝宝给挡住了,我们来更改一下它的位置。我们要是想让提示显示在图片下面,只要把垂直方向向下移动子元素的高度一半距离

Tooltip(
  // 817和806是原图大小,250是设置显示的宽度, 817 * 250 / 806计算当前高度
  verticalOffset: 817 * 250 / 806 / 2,
  ...
)
复制代码

image

Tooltip中只有一个设置垂直距离的属性,那要是我们想让它右边或左边显示怎么办?我们可以使用margin这个属性

Tooltip(
  margin: const EdgeInsets.only(left: 250),
  ...
)
复制代码

image

提示虽然显示到右边去了,但是还是会遮住图片(这里背景是透明,所以不太能看出效果)。我们怎么才能让它显示在图片外的最右边呢?把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),
),
复制代码

image

猜你喜欢

转载自juejin.im/post/7086730755795058696