简体   繁体   中英

Flutter Transform.scale for child widgets not scaling proportionately, why?

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 (eg 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,
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM