I need to know the exact bounds a piece of text -- the equivalent of getTextBounds for Android. I realize this goes somewhat counter to Flutter's design, but I am using text in a non-traditional way (as if the text were, say, embedded into an artistic picture at a precise location and size).
I've tried three methods:
TextPainter
'sminIntrinsicWidth
andheight
. Source below. This produces a bounding box with space on all sides:I need the sides of that rectangle to be right up against the black pixels of the '8'. (In this particular case,
width
andmaxIntrinsicWidth
give the same value asminIntrinsicWidth
; also,preferredLineHeight
gives the same value asheight
.)Paragraph
'sgetBoxesForRange
-- basically the same result as with TextPainter.FittedBox
-- also leaves spaces, no matter theBoxFit
enum value. I used this answer as a starting point.
TextPainter
code follows. (I realize this is inefficient; I don't care until I get the needed bounding box. I used Scene/Picture/etc in hopes of finding appropriate functionality in the lower levels.)
import 'dart:ui';
import 'dart:typed_data';
import 'package:flutter/painting.dart';
const black = Color(0xff000000);
const white = Color(0xffffffff);
final identityTransform = new Float64List(16)
..[0] = 1.0
..[5] = 1.0
..[10] = 1.0
..[15] = 1.0;
TextPainter createTextPainter() {
return new TextPainter(
text: new TextSpan(
text: '8',
style: new TextStyle(
color: black,
fontSize: 200.0,
fontFamily: "Roboto",
),
),
textDirection: TextDirection.ltr,
)..layout();
}
void drawBackground(Canvas canvas, Rect screen) {
canvas.drawRect(
screen,
new Paint()
..color = white
..style = PaintingStyle.fill);
}
Picture createPicture() {
final recorder = new PictureRecorder();
final screen = Offset.zero & window.physicalSize;
final canvas = new Canvas(recorder, screen);
final offset = screen.center;
final painter = createTextPainter();
final bounds = offset & Size(painter.minIntrinsicWidth, painter.height);
drawBackground(canvas, screen);
painter.paint(canvas, offset);
canvas.drawRect(
bounds,
new Paint()
..color = black
..style = PaintingStyle.stroke
..strokeWidth = 3.0);
return recorder.endRecording();
}
Scene createScene() {
final builder = new SceneBuilder()
..pushTransform(identityTransform)
..addPicture(Offset.zero, createPicture())
..pop();
return builder.build();
}
void beginFrame(Duration timeStamp) {
window.render(createScene());
}
void main() {
window.onBeginFrame = beginFrame;
window.scheduleFrame();
}