Hello!
I am trying to make a table, but i have many column headers, and if you put them all next to each other, they take up too much horizontal space.
So i’m trying to rotate them 45 degrees to save space, like shown here:
RotationTransition(turns: AlwaysStoppedAnimation(7/8)) and Transform.rotate keep the original width (it does layout calculations first, and only rotates before drawing). So the end result is that i get my rotations, but i don’t get the benefit of them, i still use way too much horizontal space
RotatedBox uses width/height after rotation, during layout - perfect for my needs - but only supports 90degree rotations, not 45! Using 45 degrees would mean having to rotate your head too much to try to read the text…
Using a very long Stack to position the rotated widgets just-so, and
Writing your own RenderObject. This is probably not required, but if you can’t get the Stack working right (because you don’t have enough layout information in the build phase), then boy do I have a video for you.
Given that this looks like a spreadsheet, I suspect you may also need 2D scrolling. Luckily, Kate Lovett hosted an episode of The Flutter Build Show covering that, too.
One other idea is to combine your two approaches. First, rotate by 90 degrees so that the labels take less horizontal space. Then use Transform.rotate to make them diagonal (and therefore more readable).
normally in a row you could solve this with Expanded() but in this case it doesn’t seem to work. ideally i want them all to be equally long, and equalling the length or whichever is the longest one (and no longer than needed, but also not shorter, to avoid wrapping. but this requires constraining the row to a very precise width.
the other issue is, you need to be able to calculate the correct padding to use left and right, not sure how to do that.
i seem to have found an incredible hacky solution to give them all the same “as-small-as-needed” width… every value becomes a stack where we draw on top of every other value (with opacity 0)…
I think you’re almost there. I’m not at a computer but I think there’s a way to define the pivot point around which to Transform.rotate(). You’re currently rotating around the center.
If there’s no such argument to Transform.rotate(), there’s always the manual way to do it. But first, just see if there a parameter you can provide, or search the internet for “Flutter rotate around point” or something like that.
i had the rotation around the bottom centerpoint working, but the issue was that the texts had differing lengths (which results in non-aligned rotation points). but i found an ugly workaround for that (see my above comments)
i pretty much got it working. hacky, but still…
Widget headers() {
// when column headers are horizontal, they take too much space
// when they are vertical, you have to twist your neck to read them
// so we want 45 degree rotation to make them more compact horizontally, but still readable.
// However:
// * RotationTransition(turns: AlwaysStoppedAnimation(7/8)) and Transform.rotate keep the original width (making the rotation pointless)
// * RotatedBox uses width/height afer rotation, during layout - perfect for what we need - but only supports 90degree rotations, not 45.
// * OverflowBox(Transform.rotate) results in errors
// So the solution is to first vertically rotate the with RotatedBox, so the layout engine uses the constraints of tall&narrow text boxes,
// and after layouting, turn it by 45 degrees to make it more legible
//
// hack: create a stack of (invisible) text boxes on top of each other
// the resulting widget will have the width of whichever is the longest of the text boxes
// therefore, by stacking each entry on top of this stack, they all have the same length
// and therefore, consistent rotation origins
final all = ProgramGroup.values
.map((e) => Opacity(
opacity: 0,
child: Text(
e.name.camelToSpace(),
),
))
.toList();
return Transform.translate(
offset: const Offset(
0, -10), // because we pivot around bottom center, raise text up a bit
child: Row(
children: ProgramGroup.values
.map((e) => Transform.rotate(
alignment: Alignment.bottomCenter,
angle: pi / 4,
child: RotatedBox(
quarterTurns: 3,
child: Container(
// color: Colors.yellow,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Stack(children: [
SizedBox(
height: 26, child: Text(e.name.camelToSpace())),
...all
]),
),
),
)))
.toList()),
);
}
Yeah, if you need things like correct hitboxes and such, then @CraigLabenz’s approach might be a better fit. Namely, writing your own RenderObject. It’s a bit more involved but you have full control. His video on the topic is a great start.
Hello!
making my own RenderObject seems a bit “scary”, i rather stick with more standard widgets rather than investing time into learning something i will rarely need and will probably forget how it works when i look at the code again in a year.
so i’m using the various techniques described above. the biggest downside is the incorrect hitboxes. but i can live with that for now.
if you’re curious what my current version looks like, you can see it in action on https://www.youtube.com/watch?v=aOri5XEApi0 (skip to 3:30)
of course, if you want to give it a shot, i won’t stop you and will be happy to check it out, but no pressure at all!
Flutter and the related logo are trademarks of Google LLC. We are not endorsed by or affiliated with Google LLC.
Using contents of this forum for the purposes of training proprietary AI models is forbidden. Only if your AI model is free & open source, go ahead and scrape.