【Flutter】 如何自己实现一个通用的弹出层(Tips)组件
需求:
像这种点击一个小图标,在附近弹出一个小对话框的需求也是很频繁了。这种需求用flutter 如何实现了。
分析:
- 首先我们要实现组件在屏幕任意位置弹出
- 我们要获取需要弹出组件的位置信息
- 最好不要和点击的组件有太大的关联,可以在任何组件上使用
- 弹出的组件最好可以自定义
所以主要就围绕在如何获取目标组件的位置,和如何弹出一个全局悬浮的组件上了。
一、解决悬浮问题
我们自然不能利用stack
组件达到堆叠的效果,那样的话牵扯到了外部组件,对于外部的组件太不友好了。这里的话我使用的是Overlay
来实现。
我们通过 Overlay
可以就在屏幕上插入一个悬浮层。
final youerTips = OverlayEntry(builder:(ctx,) => <弹出的组件样式> )
//插入一个悬浮组件
Overlay.of(context)?.insert(youerTips);
//移除你的悬浮组件
youerTips?.remove();
二、如何获取组件的组件的点击位置
通过GlobalKey
拿到渲染对象,即可获取它在屏幕中的位置和它本身的宽高,这样可以很好地设置弹出层需要在的位置。
RenderBox box =
widgetGlobalKey.currentContext?.findRenderObject() as RenderBox;
//所在全局得位置
Offset position = box.localToGlobal(Offset.zero);
// 组件的大小信息
box.size
三、完整代码
import 'package:flutter/material.dart';
import 'package:sales_point/common.dart';
import 'package:sales_point/generated/assets.dart';
///一个tip组件
class PopupTips extends StatefulWidget {
const PopupTips({Key? key, this.child, required this.tips}) : super(key: key);
final Widget? child;
final String tips;
@override
State<PopupTips> createState() => _PopupTipsState();
}
class _PopupTipsState extends State<PopupTips> {
final GlobalKey childKey = GlobalKey();
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapDown: (details) {
RenderBox box =
childKey.currentContext?.findRenderObject() as RenderBox;
Offset position = box.localToGlobal(Offset.zero);
//调用显示tips
showTips(
context,
Offset(
position.dx + box.size.width / 2,
position.dy + box.size.height,
),
);
},
child: Container(
key: childKey,
//如果没有外部的点击组件可以自己设置一个默认组件
child: widget.child ??
Image.asset(
Assets.icon16InfoG,
width: 12,
height: 12,
),
),
);
}
///显示一个Tips的方法
showTips(BuildContext context, Offset position) {
OverlayEntry? tipsOverlay;
tipsOverlay = OverlayEntry(builder: (ctx) {
return Stack(
children: [
Positioned(
//减去了文字一半的长度,让tips居中,这个位置可以自己根据需求调整
left: position.dx + 12 - (widget.tips.length / 2 * 12.sp),
top: position.dy,
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.imgHomepageBubbleGW,
),
fit: BoxFit.fill),
),
padding:
const EdgeInsets.only(top: 11, bottom: 7, left: 8, right: 8),
child: Text(
widget.tips,
style: TextStyle(color: Colors.white, fontSize: 12.sp),
),
),
),
//移除tips
Positioned.fill(child: GestureDetector(
onTap: () {
tipsOverlay?.remove();
},
))
],
);
});
Overlay.of(context)?.insert(tipsOverlay);
}
}
四、使用
PopupTips(
tips: "tips内容",
child: Text("你来点我呀"),
)
Bye~
转载自:https://juejin.cn/post/7239617977363726395