204

I have widgets in a stack so I'd like to position my button bar in the bottom center of the stack but nothing works. The widget just sticks to the left side. here is my code.

new Positioned(
            bottom: 40.0,
            child: new Container(
              margin: const EdgeInsets.all(16.0),
              child: new Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  new Align(
                    alignment: Alignment.bottomCenter,
                    child: new ButtonBar(
                      alignment: MainAxisAlignment.center,
                      children: <Widget>[
                        new OutlineButton(
                          onPressed: () {
                            Navigator.push(
                                context,
                                new MaterialPageRoute(
                                    builder: (context) => new LoginPage()));
                          },
                          child: new Text(
                            "Login",
                            style: new TextStyle(color: Colors.white),
                          ),
                        ),
                        new RaisedButton(
                          color: Colors.white,
                          onPressed: () {
                            Navigator.push(
                                context,
                                new MaterialPageRoute(
                                    builder: (context) =>
                                        new RegistrationPage()));
                          },
                          child: new Text(
                            "Register",
                            style: new TextStyle(color: Colors.black),
                          ),
                        )
                      ],
                    ),
                  )
                ],
              ),
            ),
          )

I have literally tried every center alignment, please help

spongyboss
  • 8,016
  • 15
  • 48
  • 65

11 Answers11

408

You can use the Positioned.fill with Align inside a Stack:

Stack(
  children: <Widget>[      
    Positioned.fill(
      child: Align(
        alignment: Alignment.centerRight,
        child: ....                
      ),
    ),
  ],
),
Mehul Kabaria
  • 6,404
  • 4
  • 25
  • 50
Yousif khalid
  • 5,801
  • 3
  • 18
  • 23
  • 17
    @JoãoAbrantes when calling Positioned.fill(), you are getting the full size (it will fill the view), then Align can do whatever it wants inside it. If you replaced the Align with a container with a red background, the stack would get all red. – Bernardo Ferrari May 15 '20 at 17:56
  • 1
    i only used aligned and it did a job – Jakub S. Apr 24 '22 at 13:27
367

Probably the most elegant way.

You can simply use the alignment option present in Stack

child: Stack(
  alignment: Alignment.center
)
Sunit Gautam
  • 5,495
  • 2
  • 18
  • 31
78

For anyone who is reaching here and is not able to solve their issue, I used to make my widget horizontally center by setting both right and left to 0 like below:

Stack(
  children: <Widget>[
    Positioned(
      top: 100,
      left: 0,
      right: 0,
      child: Text("Search",
        style: TextStyle(
          color: Color(0xff757575),
          fontWeight: FontWeight.w700,
          fontFamily: "Roboto",
          fontStyle: FontStyle.normal,
          fontSize: 56.0,
        ),
        textAlign: TextAlign.center,
      ),
    ),
  ]
)
NaKib
  • 530
  • 5
  • 13
Amir Ghezelbash
  • 2,195
  • 15
  • 24
76

Remove everything, but this:

Align(
  alignment: Alignment.bottomCenter,
  child: new ButtonBar(
    alignment: MainAxisAlignment.center,
    children: <Widget>[
      new OutlineButton(
        onPressed: () {
          Navigator.push(
            context,
            new MaterialPageRoute(
              builder: (context) => new LoginPage()));
        },
        child: new Text(
          "Login",
          style: new TextStyle(color: Colors.white),
        ),
      ),
      new RaisedButton(
        color: Colors.white,
        onPressed: () {
          Navigator.push(
            context,
            new MaterialPageRoute(
              builder: (context) =>
                new RegistrationPage()));
        },
        child: new Text(
          "Register",
          style: new TextStyle(color: Colors.black),
        ),
      )
    ],
  ),
)

In my theory, the additional Container is destroying it. I would advise you to just surround this by adding Padding:

Padding(
  padding: EdgeInsets.only(bottom: 20.0),
  child: Align...
),

This seems a lot more reasonable to me than the Positioned and also I do not quite understand your Column with a single child only.

Apoleo
  • 2,045
  • 2
  • 21
  • 37
creativecreatorormaybenot
  • 114,516
  • 58
  • 291
  • 402
22

Thanks to all of the above answers I'd like to share something that may come in handy in some certain cases. So lets see what happens when you use Positioned:( right: 0.0, left:0.0, bottom:0.0) :

      Padding(
        padding: const EdgeInsets.all(4.0),
        child: Stack(
          children: <Widget>[
            Positioned(
                bottom: 0.0,
                right: 0.0,
                left: 0.0,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: Container(
                      color: Colors.blue,
                      child: Center(
                        child: Text('Hello',
                          style: TextStyle(color: Color(0xffF6C37F),
                          fontSize: 46, fontWeight: FontWeight.bold),),
                      )
                  ),
                )
            ),
          ],
        ),
      ),

This would be the output of the above code:

enter image description here

As you can see it would fill the whole width with the container even though you don't want it and you just want the container to wrap its children. so for this you can try trick below:

      Padding(
        padding: const EdgeInsets.all(4.0),
        child: Stack(
          children: <Widget>[
            Positioned(
                bottom: 0.0,
                right: 0.0,
                left: 0.0,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Container(),
                    Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 8.0),
                      child: Container(
                          color: Colors.blue,
                          child: Text('Hello',
                            style: TextStyle(color: Color(0xffF6C37F), 
                            fontSize: 46, fontWeight: FontWeight.bold),)
                      ),
                    ),
                    Container(),
                  ],
                )
            ),
          ],
        ),
      ),

enter image description here

Taba
  • 3,850
  • 4
  • 36
  • 51
14

You can change the Positioned with Align inside a Stack:

Align(
  alignment: Alignment.bottomCenter,
  child: ... ,
),

For more info about Stack: Exploring Stack

Marco
  • 676
  • 8
  • 12
  • the best solution so far, especially for positioning `Text`s. `Positioned` with `left:0` and `right:0` expands the actual widget horizontally. – Osman Jul 11 '23 at 11:30
11

The Problem is the Container that gets the smallest possible size.

Just give a width: to the Container (in red) and you are done.

width: MediaQuery.of(context).size.width

enter image description here

  new Positioned(
  bottom: 0.0,
  child: new Container(
    width: MediaQuery.of(context).size.width,
    color: Colors.red,
    margin: const EdgeInsets.all(0.0),
    child: new Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        new Align(
          alignment: Alignment.bottomCenter,
          child: new ButtonBar(
            alignment: MainAxisAlignment.center,
            children: <Widget>[
              new OutlineButton(
                onPressed: null,
                child: new Text(
                  "Login",
                  style: new TextStyle(color: Colors.white),
                ),
              ),
              new RaisedButton(
                color: Colors.white,
                onPressed: null,
                child: new Text(
                  "Register",
                  style: new TextStyle(color: Colors.black),
                ),
              )
            ],
          ),
        )
      ],
    ),
  ),
),
chemamolins
  • 19,400
  • 5
  • 54
  • 47
1

Have a look at this solution I came up with

Positioned( child: SizedBox( child: CircularProgressIndicator(), width: 50, height: 50,), left: MediaQuery.of(context).size.width / 2 - 25);

RIX
  • 105
  • 2
  • 7
1

The Best way worked for me, was using Align. I needed to make the profile picture of a user in the bottom center of the Cover picture.

return Container(
  height: 220,
  color: Colors.red,
  child: Stack(
    children: [
      Container(
        height: 160,
        color: Colors.yellow,
      ),
      Align(
        alignment: Alignment.bottomCenter,
        child: UserProfileImage(),
      ),
    ],
  ),
);

This worked like a charm.

theCaptainXgod
  • 223
  • 1
  • 7
0

It can work like Positioned.center You determine the center of the widget and set the same center of widget and point.

import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:math' as math;

class AlignPositioned extends SingleChildRenderObjectWidget {
  const AlignPositioned({
    Key? key,
    this.alignment = Alignment.center,
    required this.centerPoint,
    this.widthFactor,
    this.heightFactor,
    Widget? child,
  })  : assert(widthFactor == null || widthFactor >= 0.0),
        assert(heightFactor == null || heightFactor >= 0.0),
        super(key: key, child: child);

  final AlignmentGeometry alignment;
  final Offset centerPoint;

  final double? widthFactor;

  final double? heightFactor;

  @override
  _RenderPositionedBox createRenderObject(BuildContext context) {
    return _RenderPositionedBox(
      alignment: alignment,
      widthFactor: widthFactor,
      heightFactor: heightFactor,
      textDirection: Directionality.maybeOf(context),
      centerPoint: this.centerPoint,
    );
  }

  @override
  void updateRenderObject(
      BuildContext context, _RenderPositionedBox renderObject) {
    renderObject
      ..alignment = alignment
      ..widthFactor = widthFactor
      ..heightFactor = heightFactor
      ..textDirection = Directionality.maybeOf(context)
      ..centerPoint = centerPoint;
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties
        .add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
    properties
        .add(DoubleProperty('widthFactor', widthFactor, defaultValue: null));
    properties
        .add(DoubleProperty('heightFactor', heightFactor, defaultValue: null));
  }
}

class _RenderPositionedBox extends RenderAligningShiftedBox {
  Offset centerPoint;

  _RenderPositionedBox({
    RenderBox? child,
    double? widthFactor,
    double? heightFactor,
    AlignmentGeometry alignment = Alignment.center,
    TextDirection? textDirection,
    required this.centerPoint,
  })  : assert(widthFactor == null || widthFactor >= 0.0),
        assert(heightFactor == null || heightFactor >= 0.0),
        _widthFactor = widthFactor,
        _heightFactor = heightFactor,
        super(child: child, alignment: alignment, textDirection: textDirection);

  double? get widthFactor => _widthFactor;
  double? _widthFactor;

  set widthFactor(double? value) {
    assert(value == null || value >= 0.0);
    if (_widthFactor == value) return;
    _widthFactor = value;
    markNeedsLayout();
  }

  set alignment(AlignmentGeometry value) {
    super.alignment = value;
    _resolvedAlignment = alignment.resolve(textDirection);
  }

  double? get heightFactor => _heightFactor;
  double? _heightFactor;
  late Alignment _resolvedAlignment = alignment.resolve(textDirection);

  set heightFactor(double? value) {
    assert(value == null || value >= 0.0);
    if (_heightFactor == value) return;
    _heightFactor = value;
    markNeedsLayout();
  }

  @override
  Size computeDryLayout(BoxConstraints constraints) {
    final bool shrinkWrapWidth =
        _widthFactor != null || constraints.maxWidth == double.infinity;
    final bool shrinkWrapHeight =
        _heightFactor != null || constraints.maxHeight == double.infinity;
    if (child != null) {
      final Size childSize = child!.getDryLayout(constraints.loosen());
      return constraints.constrain(Size(
        shrinkWrapWidth
            ? childSize.width * (_widthFactor ?? 1.0)
            : double.infinity,
        shrinkWrapHeight
            ? childSize.height * (_heightFactor ?? 1.0)
            : double.infinity,
      ));
    }
    return constraints.constrain(Size(
      shrinkWrapWidth ? 0.0 : double.infinity,
      shrinkWrapHeight ? 0.0 : double.infinity,
    ));
  }

  @override
  void performLayout() {
    final BoxConstraints constraints = this.constraints;
    final bool shrinkWrapWidth =
        _widthFactor != null || constraints.maxWidth == double.infinity;
    final bool shrinkWrapHeight =
        _heightFactor != null || constraints.maxHeight == double.infinity;

    if (child != null) {
      child!.layout(constraints.loosen(), parentUsesSize: true);
      size = constraints.constrain(Size(
        shrinkWrapWidth
            ? child!.size.width * (_widthFactor ?? 1.0)
            : double.infinity,
        shrinkWrapHeight
            ? child!.size.height * (_heightFactor ?? 1.0)
            : double.infinity,
      ));

      final BoxParentData childParentData = child!.parentData! as BoxParentData;
      final moveX = _resolvedAlignment.x - 1;
      final moveY = _resolvedAlignment.y - 1;
      log(_resolvedAlignment.y.toString());
      childParentData.offset = this.centerPoint +
          Offset(
            child!.size.width / 2 * moveX,
            child!.size.height / 2 * moveY,
          );
      // log(_resolvedAlignment.x.toString());
      // log(_resolvedAlignment.y.toString());

      // _resolvedAlignment.alongOffset(size - child!.size as Offset);
    } else {
      size = constraints.constrain(Size(
        shrinkWrapWidth ? 0.0 : double.infinity,
        shrinkWrapHeight ? 0.0 : double.infinity,
      ));
    }
  }

  @override
  void debugPaintSize(PaintingContext context, Offset offset) {
    super.debugPaintSize(context, offset);
    assert(() {
      final Paint paint;
      if (child != null && !child!.size.isEmpty) {
        final Path path;
        paint = Paint()
          ..style = PaintingStyle.stroke
          ..strokeWidth = 1.0
          ..color = const Color(0xFFFFFF00);
        path = Path();
        final BoxParentData childParentData =
            child!.parentData! as BoxParentData;
        if (childParentData.offset.dy > 0.0) {
          // vertical alignment arrows
          final double headSize =
              math.min(childParentData.offset.dy * 0.2, 10.0);
          path
            ..moveTo(offset.dx + size.width / 2.0, offset.dy)
            ..relativeLineTo(0.0, childParentData.offset.dy - headSize)
            ..relativeLineTo(headSize, 0.0)
            ..relativeLineTo(-headSize, headSize)
            ..relativeLineTo(-headSize, -headSize)
            ..relativeLineTo(headSize, 0.0)
            ..moveTo(offset.dx + size.width / 2.0, offset.dy + size.height)
            ..relativeLineTo(0.0, -childParentData.offset.dy + headSize)
            ..relativeLineTo(headSize, 0.0)
            ..relativeLineTo(-headSize, -headSize)
            ..relativeLineTo(-headSize, headSize)
            ..relativeLineTo(headSize, 0.0);
          context.canvas.drawPath(path, paint);
        }
        if (childParentData.offset.dx > 0.0) {
          // horizontal alignment arrows
          final double headSize =
              math.min(childParentData.offset.dx * 0.2, 10.0);
          path
            ..moveTo(offset.dx, offset.dy + size.height / 2.0)
            ..relativeLineTo(childParentData.offset.dx - headSize, 0.0)
            ..relativeLineTo(0.0, headSize)
            ..relativeLineTo(headSize, -headSize)
            ..relativeLineTo(-headSize, -headSize)
            ..relativeLineTo(0.0, headSize)
            ..moveTo(offset.dx + size.width, offset.dy + size.height / 2.0)
            ..relativeLineTo(-childParentData.offset.dx + headSize, 0.0)
            ..relativeLineTo(0.0, headSize)
            ..relativeLineTo(-headSize, -headSize)
            ..relativeLineTo(headSize, -headSize)
            ..relativeLineTo(0.0, headSize);
          context.canvas.drawPath(path, paint);
        }
      } else {
        paint = Paint()..color = const Color(0x90909090);
        context.canvas.drawRect(offset & size, paint);
      }
      return true;
    }());
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties
        .add(DoubleProperty('widthFactor', _widthFactor, ifNull: 'expand'));
    properties
        .add(DoubleProperty('heightFactor', _heightFactor, ifNull: 'expand'));
  }
}
Hellomik U
  • 496
  • 5
  • 12
-2

You can try this too:

Center(
  child: Stack(
    children: [],
  ),
)
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440