Skip to content

Conversation

@letsar
Copy link
Contributor

@letsar letsar commented Nov 17, 2018

In some cases it can be helpful to position a widget inside a Stack relatively to the size of the Stack.

This PR adds a way to do this by setting a new value of the Positioned widget (isRelative) to true.

@zoechi zoechi added the framework flutter/packages/flutter repository. See also f: labels. label Nov 28, 2018
@letsar
Copy link
Contributor Author

letsar commented Dec 6, 2018

With the isRelative field, every field is considered relative, and if the user wants to mix absolute and relative positioning he can't. So I'm wondering if it would not be better if I add 4 other fields like bottomFactor, leftFactor, etc. instead of the isRelative field.

What do you think about it @Hixie?

@Hixie
Copy link
Contributor

Hixie commented Jan 28, 2019

@letsar What's the motivating use case here? Can you describe in more detail what you are trying to solve? (as per https://github.com/flutter/flutter/wiki/Tree-hygiene#overview normally we'd file a bug first for API changes)

I can imagine doing something similar to what you describe today using a combination of Align and FractionallySizedBox, but I'm not sure it would solve the same problem you are having. It's hard to evaluate proposals without a concrete use case.

@Hixie
Copy link
Contributor

Hixie commented Jan 28, 2019

(props for writing tests by the way! thanks!)

@Hixie
Copy link
Contributor

Hixie commented Jan 28, 2019

(@goderbauer and I spoke about the design of this one... we think it's an issue that the ParentData gets mutated by the resolve(), but the overall idea is interesting. I could imagine having the StackParentData have a field that's an object that represents the RelativeRect (rather than it having top/left/width/etc), and then that object would have a resolve that takes a Size (and maybe a TextDirection) and returns a RelativeRect. PositionedDirectional could then be changed to work with this new API, and we could add a Positioned.fractional that works similarly to what you're describing here. That avoids having a boolean that changes the behaviour, which is always a bit sketchy, and also it would make it easy to extend this later to support even more fancy options, whatever those might be.)

@letsar
Copy link
Contributor Author

letsar commented Jan 28, 2019

Hi @Hixie, sorry I should have created an issue for this before. I will do better next time.

This is my use case:
I have a widget inside a Stack.
I want the left position of my widget at 20% of the Stack's size, its top at 5%, its right at 10%, and the bottom at 30%.
If the stack has a size of 100x100, this widget would be positioned at (left, top)=(20, 5) and with a size (width, height)=(70, 65)
I didn't find how to do it with a combination of Align and FractionallySizedBox. For the moment I use a LayoutBuilder to know the size of the Stack and I compute the left,top,right and bottom values of a Positioned widget, but I don't like this solution.

So I thought it could be a good idea to add a way to create a fractional Positioned widget. I played with the Positioned widget and found a way to do it, so I made this PR.
But yeah, I'm not quite satisfied with the API I provided, and what you suggested is better I think :-). I should try to implement it if you find this use case interesting.

@goderbauer
Copy link
Member

goderbauer commented Jan 29, 2019

This seems to be doing what you describe with Align and FractionallySizedBox:

import 'package:flutter/material.dart';

void main() => runApp(MyDemoWidget());

class MyDemoWidget extends StatelessWidget {

  @override
  Widget build(BuildContext context) {

    // The child should have a width of 70% of the stack's width.
    const double widthFactor = 0.7;
    // The child should have a height of 65% of the stack's height.
    const double heightFactor = 0.65;
    // The child's left edge should be indented at 20% of the stack's width.
    const double leftFactor = 0.2;
    // The child's top edge should be indented at 5% of the stack's height.
    const double topFactor = 0.05;

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('DEMO'),
        ),
        body: Center(
          child: SizedBox(
            height: 100.0,
            width: 100.0,
            child: Stack(
              children: <Widget>[
                Container(
                  color: Colors.green,
                ),
                Align(
                  alignment: FractionalOffset(
                    leftFactor / (1.0 - widthFactor),
                    topFactor / (1.0 - heightFactor),
                  ),
                  child: FractionallySizedBox(
                    widthFactor: widthFactor,
                    heightFactor: heightFactor,
                    child: Container(
                      color: Colors.yellow,
                    )
                  ),
                )
              ],
            ),
          )
        ),
      ),
    );
  }
}

The math for the alignment is a little ugly. Maybe we could encapsulate the Align and FractionallySizedBox in a separate Widget, something like FractionallyAlignedSizedBox - possibly with a better name?

img_0006

The Math

@letsar
Copy link
Contributor Author

letsar commented Jan 30, 2019

Oh great!!! It looks like my PR wasn't needed after all, I really should have created an issue before 🙂 .

Yes the math is not really straightforward 😄 , and I think it would be better if we have a widget to encapsulate this like you suggested. FractionallyAlignedSizedBox seems to be a good name, but I'm not sure if people who look for positioning a widget relative to the size of its parent would find it easily 😕.

The advantage or your solution is that it's also working outside a Stack 👍 .

@goderbauer
Copy link
Member

@letsar Would it be ok to close this PR then and you file a feature request for such a widget at https://github.com/flutter/flutter/issues/new/choose requesting such a Widget? We can then discuss names and how that would work with text directionality over there.

@letsar
Copy link
Contributor Author

letsar commented Feb 5, 2019

@goderbauer Yes no problem. I will file this feature request.

@letsar letsar closed this Feb 5, 2019
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants