Last active
February 29, 2024 14:09
-
-
Save CaiJingLong/bb610e06d8e28b71bc7048dfd5151146 to your computer and use it in GitHub Desktop.
Use Offstage widget to measure the widget size.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'dart:async'; | |
| import 'package:flutter/material.dart'; | |
| import 'package:vector_math/vector_math_64.dart' show Vector3; | |
| class MeasureWidget extends StatefulWidget { | |
| const MeasureWidget({ | |
| Key? key, | |
| required this.child, | |
| required this.measureRect, | |
| required this.boxConstraints, | |
| }) : super(key: key); | |
| final Widget child; | |
| final ValueSetter<Rect?> measureRect; | |
| final BoxConstraints boxConstraints; | |
| @override | |
| MeasureWidgetState createState() => MeasureWidgetState(); | |
| } | |
| class MeasureWidgetState extends State<MeasureWidget> { | |
| GlobalKey key = GlobalKey(); | |
| @override | |
| void initState() { | |
| super.initState(); | |
| WidgetsBinding.instance?.addPostFrameCallback(afterFirstLayout); | |
| } | |
| @override | |
| void dispose() { | |
| super.dispose(); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| return Offstage( | |
| child: Center( | |
| child: Container( | |
| key: key, | |
| // constraints: widget.boxConstraints, | |
| child: widget.child, | |
| ), | |
| ), | |
| ); | |
| } | |
| void afterFirstLayout(Duration context) { | |
| final Rect? rect = UIHelper.findGlobalRect(key); | |
| widget.measureRect.call(rect); | |
| } | |
| } | |
| class UIHelper { | |
| UIHelper._(); | |
| static Rect? findGlobalRect(GlobalKey key) { | |
| final RenderObject? renderObject = key.currentContext?.findRenderObject(); | |
| if (renderObject == null) { | |
| return null; | |
| } | |
| if (renderObject is RenderBox) { | |
| final Offset globalOffset = renderObject.localToGlobal(Offset.zero); | |
| Rect bounds = renderObject.paintBounds; | |
| bounds = bounds.translate(globalOffset.dx, globalOffset.dy); | |
| return bounds; | |
| } else { | |
| Rect bounds = renderObject.paintBounds; | |
| final Vector3 translation = | |
| renderObject.getTransformTo(null).getTranslation(); | |
| bounds = bounds.translate(translation.x, translation.y); | |
| return bounds; | |
| } | |
| } | |
| static Future<Rect> measureWidgetRect({ | |
| required BuildContext context, | |
| required Widget widget, | |
| required BoxConstraints boxConstraints, | |
| }) { | |
| final Completer<Rect> completer = Completer<Rect>(); | |
| OverlayEntry? entry; | |
| entry = OverlayEntry(builder: (BuildContext ctx) { | |
| print(Theme.of(context).platform); | |
| return Material( | |
| child: MeasureWidget( | |
| boxConstraints: boxConstraints, | |
| measureRect: (Rect? rect) { | |
| entry?.remove(); | |
| completer.complete(rect); | |
| }, | |
| child: widget, | |
| ), | |
| ); | |
| }); | |
| Overlay.of(context)?.insert(entry); | |
| return completer.future; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'dart:async'; | |
| import 'package:flutter/material.dart'; | |
| class MeasureWidget extends StatefulWidget { | |
| final Widget child; | |
| final ValueSetter<Rect> measureRect; | |
| final BoxConstraints boxConstraints; | |
| const MeasureWidget({ | |
| Key key, | |
| this.child, | |
| this.measureRect, | |
| this.boxConstraints, | |
| }) : super(key: key); | |
| @override | |
| MeasureWidgetState createState() => MeasureWidgetState(); | |
| } | |
| class MeasureWidgetState extends State<MeasureWidget> { | |
| GlobalKey key = GlobalKey(); | |
| @override | |
| void initState() { | |
| super.initState(); | |
| WidgetsBinding.instance.addPostFrameCallback(afterFirstLayout); | |
| } | |
| @override | |
| void dispose() { | |
| super.dispose(); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| return Offstage( | |
| offstage: true, | |
| child: Center( | |
| child: Container( | |
| key: key, | |
| // constraints: widget.boxConstraints, | |
| child: widget.child, | |
| ), | |
| ), | |
| ); | |
| } | |
| void afterFirstLayout(Duration context) { | |
| Rect rect = UIHelper.findGlobalRect(key); | |
| widget.measureRect?.call(rect); | |
| } | |
| } | |
| class UIHelper { | |
| static Rect findGlobalRect(GlobalKey key) { | |
| RenderObject renderObject = key.currentContext?.findRenderObject(); | |
| if (renderObject == null) { | |
| return null; | |
| } | |
| if (renderObject is RenderBox) { | |
| var globalOffset = renderObject?.localToGlobal(Offset.zero); | |
| if (globalOffset == null) { | |
| return null; | |
| } | |
| var bounds = renderObject.paintBounds; | |
| bounds = bounds.translate(globalOffset.dx, globalOffset.dy); | |
| return bounds; | |
| } else { | |
| var bounds = renderObject.paintBounds; | |
| final translation = renderObject?.getTransformTo(null)?.getTranslation(); | |
| bounds = bounds.translate(translation.x, translation.y); | |
| return bounds; | |
| } | |
| } | |
| static Future<Rect> measureWidgetRect({ | |
| BuildContext context, | |
| Widget widget, | |
| BoxConstraints boxConstraints, | |
| }) { | |
| Completer<Rect> completer = Completer(); | |
| OverlayEntry entry; | |
| entry = OverlayEntry(builder: (BuildContext ctx) { | |
| print(Theme.of(context).platform); | |
| return Material( | |
| child: MeasureWidget( | |
| child: widget, | |
| boxConstraints: boxConstraints, | |
| measureRect: (rect) { | |
| entry.remove(); | |
| completer.complete(rect); | |
| }, | |
| ), | |
| ); | |
| }); | |
| Overlay.of(context).insert(entry); | |
| return completer.future; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
May I ask for example, pls?