I have a basic flag widget, with code here:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: Flag(),
),
);
}
}
class Flag extends StatelessWidget {
@override
Widget build(BuildContext context) {
var scaleFactor = 1.0;
final flag = Transform.scale(
scale: scaleFactor,
child: AspectRatio(
aspectRatio: 5 / 3,
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 2, color: Colors.black),
),
child: Center(
child: Container(
height: 400,
width: 150,
color: Colors.purple,
),
),
),
),
);
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) => flag,
);
}
}
It looks like this:
If I change scaleFactor to 0.5, it scales as expected:
But if I rotate my emulator to landscape, the proportions are off:
If I make the stripe proportional to the landscape view (e.g. change the stripe width to 250), it gets too big in portrait mode:
How do I ensure the purple stripe takes up the same proportion of space regardless of device size?
The flag is going to get way more complicated so I don't want to use MediaQuery.of(context).size to get the device width and calculate a percentage of that for every single child widget...
Do I need to tell my widget its "canonical" size? Do I need to pass a scaleFactor to every child widget?
Any ideas very appreciated :)
So, I see two ways to solve this, depending on what your eventual goal is. I think the first one is probably what you actually want.
1) Use a Row
and an Expanded
widget for each part of the flag, with a flex
of one. The AspectRatio
will keep the aspect ratio fixed, so the proportions should remain the same for the containers. Since the default flex factor is one anyhow, you can also just leave that out. If you need to the white parts to be transparent, just give Colors.transparent
as the color.
class Flag extends StatelessWidget {
@override
Widget build(BuildContext context) {
var scaleFactor = 1.0;
final flag = Transform.scale(
scale: scaleFactor,
child: AspectRatio(
aspectRatio: 5 / 3,
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 2, color: Colors.black),
),
child: Row(
children: <Widget>[
Expanded(
flex:1,
child: Container(
color: Colors.white,
),
),
Expanded(
flex:1,
child: Container(
color: Colors.purple,
),
),
Expanded(
flex:1,
child: Container(
color: Colors.white,
),
),
],
),
),
),
);
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) => flag,
);
}
}
2) You could just scale the contents of the center with a Transform
widget, but that will squish any content you put inside it, so that's probably not what you want.
class Flag extends StatelessWidget {
@override
Widget build(BuildContext context) {
var scaleFactor = 1.0;
final flag = Transform.scale(
scale: scaleFactor,
child: AspectRatio(
aspectRatio: 5 / 3,
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 2, color: Colors.black),
),
child: Center(
child: Transform(
transform: Matrix4.diagonal3Values(0.33, 1.0, 1.0),
alignment: Alignment.bottomCenter,
child: Container(
color: Colors.purple,
),
),
),
),
),
);
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) => flag,
);
}
}