2

I'd like to use Positioned to freely place widgets on a Stack. It looks like by default Positioned only offers to place its child using either left, right, top, or bottom. This has the behavior to align one of the boundaries to the given coordinate. What I'd like to achieve is to place the child at a certain x/y coordinate, but center it on it.

An example:

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Some App",
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      home: Scaffold(
        body: Stack(children: [
          Positioned(
            left: 100,
            top: 100,
            child: SomeChild(text: "Some child"),
          ),
          Positioned(
            left: 100,
            top: 100,
            child: Container(width: 5, height: 5, color: Colors.red.shade900),
          ),
          Positioned(
            left: 100,
            top: 150,
            child: SomeChild(text: "Some child with longer text"),
          ),
          Positioned(
            left: 100,
            top: 150,
            child: Container(width: 5, height: 5, color: Colors.red.shade900),
          ),
        ]),
      ),
    );
  }
}

class SomeChild extends StatelessWidget {
  final String text;
  const SomeChild({Key? key, required this.text}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text(text);
  }
}

Results in:

enter image description here

Example on Dartpad

Basically I'd like the children to center on the small debug gizmos.

Note: I'm using SomeChild as a placeholder for an arbitrary child whose size I neither know nor control explicitly.

Naive attempts at solving the problem where using a Center to wrap the child, but that has no effect. I also tried to move the Positioned into the children, doing some manual size determination within the children itself, so that they can shift their top and right coordiate by half their size. But that is not only awkward, and has to be implemented for every children manually, I also had problems making it work in the first place, because Stack complained that its children are no longer either a Positioned/Aligned/Container.

Is there an elegant way to center the child of a Positioned generically?


I think this question is different from that one, because there the goal is to center a child w.r.t. the Stack itself, not a certain coordinate.

bluenote10
  • 23,414
  • 14
  • 122
  • 178
  • `What I'd like to achieve is to place the child at a certain x/y coordinate, but center it on it.` what do you mean by center it on it? You mean the red dots will always be at the center of the `SomeChild` widget despite how long the words is going to be? – HeIsDying Aug 13 '21 at 02:08
  • @TryHarder Yes exactly. For instance in the case `(100, 100)` I'd like the text to be centered on `(100, 100)`, not left/right/bottom/top aligned on it. Or speaking in terms of the 5x5 red boxes: I'd like them to be at `(97.5, 102.5)` instead of `(100, 105)`. – bluenote10 Aug 13 '21 at 07:55

4 Answers4

8

If I understood correctly, you need FractionalTranslation

enter image description here

import "package:flutter/material.dart";

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Some App",
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      home: Scaffold(
        body: Stack(children: [
          Positioned(
            left: 100,
            top: 100,
            child: FractionalTranslation(
              translation: Offset(-0.5, -0.5),
              child: SomeChild(text: "Some child"),
            ),
          ),
          Positioned(
            left: 100,
            top: 100,
            child: Container(width: 5, height: 5, color: Colors.red.shade900),
          ),
          Positioned(
            left: 100,
            top: 150,
            child: FractionalTranslation(
              translation: Offset(-0.5, -0.5),
              child: SomeChild(text: "Some child with longer text"),
            ),
          ),
          Positioned(
            left: 100,
            top: 150,
            child: Container(width: 5, height: 5, color: Colors.red.shade900),
          ),
        ]),
      ),
    );
  }
}

class SomeChild extends StatelessWidget {
  final String text;

  const SomeChild({Key? key, required this.text}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text(text);
  }
}
Nagual
  • 1,576
  • 10
  • 17
  • 27
2

You can calculate the left or x value and top or y values by subtracting the width and height from the coordinates:

Size widgetSize = Size(200,100); // the size of the widget you want to position
Offset position = Offset(300,400); //the position of the widget on the screen
.
.
.
Positioned(
  left: position.dx - widgetSize.width/2,
  top: position.dy - widgetSize.height/2,
  child: ...
),

For this to work you predefine the child widget's size with the widgetSize.

Then you can put SomeChild inside a Container with that widgetSize and center it:

Positioned(
  left: position.dx - widgetSize.width/2,
  top: position.dy - widgetSize.height/2,
  child: Container(
    width: widgetSize.width,
    height: widgetSize.height,
    child: Center(
      child: SomeWidget(),
    ),
  ),
),

Note that widgetSize should be greater than the size of someWidget. You could make widgetSize gigantic in order to fit any someWidget.

MindStudio
  • 706
  • 1
  • 4
  • 13
  • While this is still helpful, the question was specifically for the case where I cannot hardcode the size of the children. As mentioned in the question: _I'm using `SomeChild` as a placeholder for an arbitrary child whose size I neither know nor control explicitly_. What if the child still exceeds the predefined size? – bluenote10 Aug 13 '21 at 07:49
  • again you could make the size like 9999999x9999999 or whatever... it is not nice but should work. I don't think anything would and should exeed this size. – MindStudio Aug 14 '21 at 01:11
0

May try this out. You can replace Positioned.fill with Positioned to suit your needs. Hope this help you out :D

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return MaterialApp(
      title: "Some App",
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      home: Scaffold(
        body: Stack(children: [
          // try replace Positioned.fill > Positioned
          Positioned.fill(
            left: 100,
            top: 100,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Container(width: 5, height: 5, color: Colors.blue),
                Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Flexible(
                      child:  SomeChild(text: "THIS IS A VERY LONG LONG TEXT, NARUHODO!!!! KJASNDKJASNDAJKNSDKJANSJKNJKANDJS"),
                    ),
                  ],
                ),
              ],
            ),
          ),
          Positioned(
            left: 100,
            top: 150,
            child: SomeChild(text: "Some child with longer text"),
          ),
          Positioned(
            left: 100,
            top: 150,
            child: Container(width: 5, height: 5, color: Colors.red.shade900),
          ),
        ]),
      ),
    );
  }
}
HeIsDying
  • 335
  • 5
  • 16
  • Thanks! But as far as I can see that only centers the debug gizmo w.r.t. the text. They are both still left aligned at `(100, 100)` and not centered on top of that coordinate. I'd like the center of an arbitrary child to be at a given `(x, y)`. Perhaps an example helps: Imagine a map application, where you know that a certain map feature is at `(x, y)`. Let's say we have multiple highlighter/marker widgets of unknown size (e.g. small circle, large circle, pulsating circle). The goal is to draw these highlighter widgets centered exactly at the given coordinate. – bluenote10 Aug 13 '21 at 12:04
-1

Row and Column widgets has axis-alignment parameter.. you can easly center a view by using them

Patrick G.
  • 458
  • 5
  • 7
  • Thanks for the suggestion! Somehow I cannot get them to work with `Positioned` though, probably for the same reason `Center` doesn't work. At least (single or double) wrapping `SomeChild` with both `Row` and `Column` and setting `mainAxisAlignment: MainAxisAlignment.center` on both doesn't have an effect. Could you illustrate how you would adapt the code exactly? – bluenote10 Aug 12 '21 at 20:17