OverlayEntry
确实是实现你提到的目标的好选择。你可以包装你的小部件,它应该创建这个覆盖,例如长按,用
GestureRecognizer
LongPressStartDetails
. 在那里你可以计算的位置和大小
覆盖入口
基于
globalPosition
MediaQuery.of(context).size
提示:移除
覆盖入口
remove()
覆盖入口
小工具本身!所以请保留对它的引用。
我用了
堆栈小部件
手势识别
检测实际小部件之外的任何点击。点击这个
集装箱
_overlayEntry.remove();
关闭覆盖。
我终于用了
具有
顶部
enum OVERLAY_POSITION { TOP, BOTTOM }
class ScriptureDisplay extends StatefulWidget {
@override
_ScriptureDisplayState createState() => _ScriptureDisplayState();
}
class _ScriptureDisplayState extends State<ScriptureDisplay> {
TapDownDetails _tapDownDetails;
OverlayEntry _overlayEntry;
OVERLAY_POSITION _overlayPosition;
double _statusBarHeight;
double _toolBarHeight;
OverlayEntry _createOverlayEntry() {
RenderBox renderBox = context.findRenderObject();
var size = renderBox.size;
var offset = renderBox.localToGlobal(Offset.zero);
var globalOffset = renderBox.localToGlobal(_tapDownDetails.globalPosition);
_statusBarHeight = MediaQuery.of(context).padding.top;
// TODO: Calculate ToolBar Height Using MediaQuery
_toolBarHeight = 50;
var screenHeight = MediaQuery.of(context).size.height;
var remainingScreenHeight = screenHeight - _statusBarHeight - _toolBarHeight;
if (globalOffset.dy > remainingScreenHeight / 2) {
_overlayPosition = OVERLAY_POSITION.TOP;
} else {
_overlayPosition = OVERLAY_POSITION.BOTTOM;
}
return OverlayEntry(builder: (context) {
return Stack(
children: <Widget>[
GestureDetector(
onTap: () {
_overlayEntry.remove();
},
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.blueGrey.withOpacity(0.1),
),
),
Positioned(
left: 10,
top: _overlayPosition == OVERLAY_POSITION.TOP
? _statusBarHeight + _toolBarHeight
: offset.dy + size.height - 5.0,
width: MediaQuery.of(context).size.width - 20,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// ignore: sdk_version_ui_as_code
if (_overlayPosition == OVERLAY_POSITION.BOTTOM)
nip(),
body(context, offset.dy),
// ignore: sdk_version_ui_as_code
if (_overlayPosition == OVERLAY_POSITION.TOP)
nip(),
],
),
)
],
);
});
}
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: 400, left: 10, right: 100),
child: GestureDetector(
child: Text("C"),
onTapDown: (TapDownDetails tapDown) {
setState(() {
_tapDownDetails = tapDown;
});
this._overlayEntry = this._createOverlayEntry();
Overlay.of(context).insert(this._overlayEntry);
},
),
);
}
Widget body(BuildContext context, double offset) {
return Material(
borderRadius: BorderRadius.all(
Radius.circular(8.0),
),
elevation: 4.0,
child: Container(
width: MediaQuery.of(context).size.width,
height: _overlayPosition == OVERLAY_POSITION.BOTTOM
? MediaQuery.of(context).size.height -
_tapDownDetails.globalPosition.dy -
20
: _tapDownDetails.globalPosition.dy -
_toolBarHeight -
_statusBarHeight -
15,
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: ListView(
padding: EdgeInsets.zero,
shrinkWrap: true,
children: [
"First",
"Second",
"Third",
"First",
"Second",
"Third",
"First",
"Second",
"Third"
]
.map((String s) => ListTile(
subtitle: Text(s),
))
.toList(growable: false),
),
),
);
}
Widget nip() {
return Container(
height: 10.0,
width: 10.0,
margin: EdgeInsets.only(left: _tapDownDetails.globalPosition.dx),
child: CustomPaint(
painter: OpenPainter(_overlayPosition),
),
);
}
}
class OpenPainter extends CustomPainter {
final OVERLAY_POSITION overlayPosition;
OpenPainter(this.overlayPosition);
@override
void paint(Canvas canvas, Size size) {
switch (overlayPosition) {
case OVERLAY_POSITION.TOP:
var paint = Paint()
..style = PaintingStyle.fill
..color = Colors.white
..isAntiAlias = true;
_drawThreeShape(canvas,
first: Offset(0, 0),
second: Offset(20, 0),
third: Offset(10, 15),
size: size,
paint: paint);
break;
case OVERLAY_POSITION.BOTTOM:
var paint = Paint()
..style = PaintingStyle.fill
..color = Colors.white
..isAntiAlias = true;
_drawThreeShape(canvas,
first: Offset(15, 0),
second: Offset(0, 20),
third: Offset(30, 20),
size: size,
paint: paint);
break;
}
canvas.save();
canvas.restore();
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => false;
void _drawThreeShape(Canvas canvas,
{Offset first, Offset second, Offset third, Size size, paint}) {
var path1 = Path()
..moveTo(first.dx, first.dy)
..lineTo(second.dx, second.dy)
..lineTo(third.dx, third.dy);
canvas.drawPath(path1, paint);
}
void _drawTwoShape(Canvas canvas,
{Offset first, Offset second, Size size, paint}) {
var path1 = Path()
..moveTo(first.dx, first.dy)
..lineTo(second.dx, second.dy);
canvas.drawPath(path1, paint);
}
}
结果