Skip to content

Instantly share code, notes, and snippets.

@CaiJingLong
Last active February 29, 2024 14:09
Show Gist options
  • Select an option

  • Save CaiJingLong/bb610e06d8e28b71bc7048dfd5151146 to your computer and use it in GitHub Desktop.

Select an option

Save CaiJingLong/bb610e06d8e28b71bc7048dfd5151146 to your computer and use it in GitHub Desktop.
Use Offstage widget to measure the widget size.
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;
}
}
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;
}
}
@minikin
Copy link

minikin commented Jan 27, 2021

May I ask for example, pls?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment