likes
comments
collection
share

【Flutter】 如何自己实现一个通用的弹出层(Tips)组件

作者站长头像
站长
· 阅读数 49

需求:

像这种点击一个小图标,在附近弹出一个小对话框的需求也是很频繁了。这种需求用flutter 如何实现了。

【Flutter】 如何自己实现一个通用的弹出层(Tips)组件

分析:

  1. 首先我们要实现组件在屏幕任意位置弹出
  2. 我们要获取需要弹出组件的位置信息
  3. 最好不要和点击的组件有太大的关联,可以在任何组件上使用
  4. 弹出的组件最好可以自定义

所以主要就围绕在如何获取目标组件的位置,和如何弹出一个全局悬浮的组件上了。

一、解决悬浮问题

我们自然不能利用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
评论
请登录