Flutter Code Snippet:获取Widget Of

2022-02-25  本文已影响0人  爱抖腿的飞飞

两种方式在Flutter页面加载完成后,获取指定Widget的位置和尺寸信息,用来显示弹窗或者新手引导。

方法一: Notification

  1. 需要自定义的class

    ///数据封装
    class PositionedNotification extends Notification {
      Offset? offset;
      Size? size;
    }
    
    class PositionedNotificationNotifier extends SingleChildRenderObjectWidget {
      const PositionedNotificationNotifier({Widget? child, Key? key})
          : super(key: key, child: child);
    
      @override
      _PositionedCallback createRenderObject(BuildContext context) {
        ///分发通知
        return _PositionedCallback(onLayoutChangedCallback: (offset, size) {
          (PositionedNotification()
                ..offset = offset
                ..size = size)
              .dispatch(context);
        });
      }
    }
    
    class _PositionedCallback extends RenderProxyBox {
      final Function(Offset?, Size?) onLayoutChangedCallback;
      Offset? tmpOffset;
      Size? tempSize;
    
      _PositionedCallback({RenderBox? child, required this.onLayoutChangedCallback})
          : super(child);
    
      @override
      void performLayout() {
        super.performLayout();
        ///widget绘制完成后,分发通知
        SchedulerBinding.instance?.addPostFrameCallback((time) {
          tmpOffset = localToGlobal(Offset.zero);
          tempSize = paintBounds.size;
          onLayoutChangedCallback(tmpOffset, tempSize);
        });
      }
    }
    
  2. 使用

    class App extends StatelessWidget {
      const App({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return NotificationListener<PositionedNotification>(
            onNotification: (notification) {
              print("Offset->${notification.offset}");
              print("Size->${notification.size}");
              return true;
            },
            child: const PositionedNotificationNotifier(child: Text("目标Widget")));
      }
    }
    

方法二: GlobalKey

  1. 定义GlobalKey

    GlobalKey globalKey = GlobalKey();
    
  2. 使用GlobalKey

    Container(
    key: globalKey,
    ...
    )
    
  3. 获取数据

      @override
      void initState() {
            ...
        SchedulerBinding.instance?.addPostFrameCallback((time) {
         BuildContext? context = globalKey.currentContext;
         RenderBox? renderBox = context?.findRenderObject() as RenderBox?;
         Offset? offset = renderBox?.localToGlobal(Offset.zero);
         Size? size = renderBox?.paintBounds.size;
        });
      }
    
  4. 如果无法直接引用GlobalKey,可以使用BuildContext.findAncestorStateOfType()

    class GlobalKeyExampleState extends State<GlobalKeyExample> {
      GlobalKey globalKey = GlobalKey();
    
      static GlobalKeyExampleState? of(BuildContext context) {
        final GlobalKeyExampleState? result =
            context.findAncestorStateOfType<GlobalKeyExampleState>();
        if (result != null) {
          return result;
        }
        return null;
      }
      ...
    }
    
    
    class ChildWidget extends StatefulWidget {
      const ChildWidget({Key? key}) : super(key: key);
    
      @override
      _ChildWidgetState createState() => _ChildWidgetState();
    }
    
    class _ChildWidgetState extends State<ChildWidget> {
      @override
      Widget build(BuildContext context) {
        GlobalKey? globalKey = GlobalKeyExampleState.of(context)?.globalKey;
        return Container(
          key: globalKey,
          ...
        );
      }
    }  
    

源码

完整示例代码见GitHub

上一篇下一篇

猜你喜欢

热点阅读