zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    11、sqlite
    10、正则
    9、bs4
    8、异常与import
    7、文件
    6、函数
    4、字典及集合
    3、元组
    1、python基本语法
    shell编程 15 --- shell 脚本调试技巧
  • 原文地址:https://www.cnblogs.com/daxueshan/p/14445924.html
Copyright © 2011-2022 走看看