• Flutter-widget相对屏幕的位置,动态展示dialog


    主要是通过 RenderObject 获取widget 相对屏幕的坐标, 从而动态设置 Dialog 的位置.

    函数   getTransformTo(RenderObject ancestor)   参数 ancestor  为null, 表示相对根组件的位置(也就是相对屏幕的位置)

    代码示例如下: 

    所点击的widget

    class CloseTap extends StatefulWidget {
      @override
      _CloseTapTapState createState() => _CloseTapTapState();
    }
    
    class _CloseTapTapState extends State<CloseTap> with WidgetsBindingObserver {
      void _onAfterRendering(Duration timeStamp) {
        RenderObject renderObject = context.findRenderObject();
        Size size = renderObject.paintBounds.size;
        var vector3 = renderObject.getTransformTo(null)?.getTranslation();
        CommonUtils.showChooseDialog(context, size, vector3);
      }
    
      @override
      Widget build(BuildContext context) {
        return GestureDetector(
          child: Icon(Icons.close),
          onTapDown: (TapDownDetails details) {
            WidgetsBinding.instance.addPostFrameCallback(_onAfterRendering);
            setState(() {});
          },
        );
      }
    }

    根据所点击的widget的坐标, 展示dialog

    class CommonUtils {
      
      static showChooseDialog(BuildContext context, Size size, var vector3) {
        final double wx = size.height;
        final double dx = vector3[0];
        final double dy = vector3[1];
        final double w = MediaQuery.of(context).size.width;
        final double h = MediaQuery.of(context).size.height;
    
        return showDialog(
          context: context,
          builder: (BuildContext context) {
            return new Material(
              color: Colors.transparent,
              child: Container(
                 double.infinity,
                height: double.infinity,
                child: Stack(
                  children: <Widget>[
                    GestureDetector(
                      child: Container(
                         double.infinity,
                        height: double.infinity,
                        child: Text(''),
                      ),
                      onTap: () {
                        Navigator.of(context).pop();
                      },
                    ),
                    Positioned(
                      left: 10.0,
                      top: dy < h / 2 ? dy + wx / 2 : null,
                      bottom: dy < h / 2 ? null : (h - dy + wx / 2),
                      child: Container(
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.all(
                            Radius.circular(10.0),
                          ),
                          color: Colors.white,
                        ),
                         w - 20.0,
                        child: GestureDetector(
                          child: Column(
                            children: <Widget>[
                              ListTile(
                                  leading: Icon(Icons.highlight_off),
                                  title: Text('不感兴趣'),
                                  subtitle: Text('减少这类内容')),
                              Divider(),
                              ListTile(
                                  leading: Icon(Icons.error_outline),
                                  title: Text('反馈垃圾内容'),
                                  subtitle: Text('低俗、标题党等')),
                              Divider(),
                              ListTile(
                                  leading: Icon(Icons.not_interested),
                                  title: Text('屏蔽'),
                                  subtitle: Text('请选择屏蔽的广告类型')),
                              Divider(),
                              ListTile(
                                leading: Icon(Icons.help_outline),
                                title: Text('为什么看到此广告'),
                              ),
                            ],
                          ),
                          onTap: () { 
                            Navigator.of(context).pop();
                          },
                        ),
                      ),
                    ),
                    Positioned(
                      left: dx - 10.0,
                      top: dy < h / 2 ? dy - wx / 2 : null,
                      bottom: dy < h / 2 ? null : (h - dy - wx / 2),
                      child: ClipPath(
                        clipper: Triangle(dir: dy - h / 2),
                        child: Container(
                           30.0,
                          height: 30.0,
                          color: Colors.white,
                          child: null,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            );
          },
        );
      }
    }

    小三角组件, 利用贝塞尔曲线api, 以及 CustomClipper 的使用

    class Triangle extends CustomClipper<Path> {
      double dir;
      Triangle({this.dir});
      @override
      Path getClip(Size size) {
        var path = Path();
        double w = size.width;
        double h = size.height;
        if (dir < 0) {
          path.moveTo(0, h);
          path.quadraticBezierTo(0, 0, w * 2 / 3, 0);
          path.quadraticBezierTo(w / 4, h / 2, w, h);
        } else {
          path.quadraticBezierTo(0, h / 2, w * 2 / 3, h);
          path.quadraticBezierTo(w / 3, h / 3, w, 0);
          path.lineTo(0, 0);
        }
        return path;
      }
    
      @override
      bool shouldReclip(CustomClipper<Path> oldClipper) => false;
    }
  • 相关阅读:
    如何修改注册表立刻生效【搜藏】
    c#怎样让picturebox出现滚动条【搜藏】
    c#怎样让程序运行出错仍继续执行【原】
    marquee标签里文本的自动换行【搜藏】
    关于HyperLink的NavigateUrl属性的链接地址带参数出错的问题【整理】
    C#程序获得星期【整理】
    sql分别获取年/月/日 函数【搜藏】
    获取本周属于本年度第几周【搜藏】
    关于ref 和 out 关键字【整理】
    hdu 1823 Luck and Love
  • 原文地址:https://www.cnblogs.com/daxueshan/p/14445924.html
Copyright © 2020-2023  润新知