Can make using OverlayEntry.
Here is sample code
final overlayEntry = OverlayEntry(
builder: (BuildContext context) => Positioned(
top: _yourCustomTop,
left: _yourCustomLeft,
child: FadeTransition(
opacity: CurvedAnimation(
parent: _yourController,
curve: Curves.fastOutSlowIn,
),
child: Material(
color: const Color(0x00ffffff),
child: Container(
decoration: ShapeDecoration(
color: Colors.white,
shape: TooltipShapeBorder(radius: 6, arrowArc: 0.2),
shadows: [
const BoxShadow(
color: Colors.black26,
blurRadius: 4.0,
offset: const Offset(2, 2),
),
],
),
child: SizedBox(
width: 84,
height: 44,
child: Center(
child: Text('_yourString'),
),
),
),
);
),
),
);
Overlay.of(context).insert(_overlayEntry);
TooltipShapeBorder
from here.
import 'package:flutter/material.dart';
class TooltipShapeBorder extends ShapeBorder {
final double arrowWidth;
final double arrowHeight;
final double arrowArc;
final double radius;
TooltipShapeBorder({
this.radius = 16.0,
this.arrowWidth = 20.0,
this.arrowHeight = 10.0,
this.arrowArc = 0.0,
}) : assert(arrowArc <= 1.0 && arrowArc >= 0.0);
@override
EdgeInsetsGeometry get dimensions => EdgeInsets.only(bottom: arrowHeight);
@override
Path getInnerPath(Rect rect, {TextDirection textDirection}) => null;
@override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
rect = Rect.fromPoints(rect.topLeft, rect.bottomRight - Offset(0, arrowHeight));
double x = arrowWidth, y = arrowHeight, r = 1 - arrowArc;
return Path()
..addRRect(RRect.fromRectAndRadius(rect, Radius.circular(radius)))
..moveTo(rect.bottomCenter.dx + x / 2, rect.bottomCenter.dy)
..relativeLineTo(-x / 2 * r, y * r)
..relativeQuadraticBezierTo(-x / 2 * (1 - r), y * (1 - r), -x * (1 - r), 0)
..relativeLineTo(-x / 2 * r, -y * r);
}
@override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {}
@override
ShapeBorder scale(double t) => this;
}