颤振位置堆栈小部件在中心

Posted

技术标签:

【中文标题】颤振位置堆栈小部件在中心【英文标题】:Flutter position stack widget in center 【发布时间】:2018-11-21 23:31:53 【问题描述】:

我在堆栈中有小部件,所以我想将我的按钮栏放在堆栈的底部中心,但没有任何效果。小部件只是粘在左侧。这是我的代码。

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),
                          ),
                        )
                      ],
                    ),
                  )
                ],
              ),
            ),
          )

我已经尝试了每个中心对齐方式,请帮助

【问题讨论】:

您在 Column 上尝试过mainAxisSize: MainAxisSize.min 吗?并通过删除 Align 小部件 是的,我试过@RémiRousselet,它仍然向左对齐 【参考方案1】:

它可以像 Positioned.center 一样工作 您确定小部件的中心并设置小部件和点的相同中心。

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'));
  

【讨论】:

【参考方案2】:

对于到达这里但无法解决问题的任何人,我曾经通过将左右都设置为 0 来使我的小部件水平居中,如下所示:

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,
      ),
    ),
  ]
)

【讨论】:

你能解释一下为什么需要左值和右值吗? Web中常用的一种做法。 ? 现在这就是我所说的简单解决方案!谢谢老哥【参考方案3】:

可能是最优雅的方式。

您可以简单地使用Stack 中的alignment 选项

child: Stack(
  alignment: Alignment.center
)

【讨论】:

确实,这是最优雅的方式。 完美运行,不会像 Positioned.fill 那样拉伸内容 迄今为止最好的答案!!可能是因为最近在 Stack 小部件中添加了此功能 确实,这应该是最佳答案。干得好! 是的,太棒了。【参考方案4】:

Stack 允许您将元素堆叠在一起,数组中的最后一个元素具有最高优先级。您可以使用AlignPositionedContainer 来定位堆栈的子级。

对齐

通过使用Alignment 设置对齐来移动小部件,它具有topCenter、bottomRight 等静态属性。或者您可以完全控制并设置Alignment(1.0, -1.0),它的 x,y 值范围为 1.0 到 -1.0,其中 (0,0) 为屏幕中心。

  Stack(
      children: [
        Align(
          alignment: Alignment.topCenter,
          child: Container(
              height: 80,
              width: 80, color: Colors.blueAccent
          ),
        ),
        Align(
          alignment: Alignment.center,
          child: Container(
              height: 80,
              width: 80, color: Colors.deepPurple
          ),
        ),
        Container(
          alignment: Alignment.bottomCenter,
          // alignment: Alignment(1.0, -1.0),
          child: Container(
              height: 80,
              width: 80, color: Colors.amber
          ),
        )
      ]
  )

【讨论】:

很好的解释,应该被接受。【参考方案5】:

对我来说最好的方法是使用Align。 我需要在封面图片的底部中心制作用户的头像。

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

这就像一个魅力。

【讨论】:

【参考方案6】:

看看我想出的这个解决方案

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

【讨论】:

【参考方案7】:

删除所有内容,但这个:

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),
        ),
      )
    ],
  ),
)

在我的理论中,额外的Container 正在摧毁它。我建议您通过添加 Padding 来包围它:

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

这对我来说似乎比Positioned 更合理,而且我不太理解你的Column 只有一个孩子。

【讨论】:

哇,谢谢,老实说,我从来不知道 Align 可以将小部件放置在 Stack 中【参考方案8】:

感谢以上所有答案,我想分享一些在某些情况下可能会派上用场的东西。那么让我们看看当你使用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),),
                      )
                  ),
                )
            ),
          ],
        ),
      ),

这将是上述代码的输出:

如您所见,即使您不想要它并且您只想让容器包裹其子项,它也会用容器填充整个宽度。因此,为此您可以尝试以下技巧:

      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(),
                  ],
                )
            ),
          ],
        ),
      ),

【讨论】:

【参考方案9】:

您可以在Stack 内使用Positioned.fillAlign

Stack(
  children: <Widget>[      
    Positioned.fill(
      child: Align(
        alignment: Alignment.centerRight,
        child: ....                
      ),
    ),
  ],
),

【讨论】:

@JoãoAbrantes 在调用 Positioned.fill() 时,您将获得完整尺寸(它将填充视图),然后 Align 可以在其中做任何它想做的事情。如果您将 Align 替换为具有红色背景的容器,则堆栈将变为红色。【参考方案10】:

你也可以试试这个:

Center(
  child: Stack(
    children: [],
  ),
)

【讨论】:

【参考方案11】:

您可以在堆栈内使用 Align 更改定位:

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

有关 Stack 的更多信息:Exploring Stack

【讨论】:

【参考方案12】:

问题是容器的尺寸尽可能小。

只需将width: 发送给容器(红色)即可。

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

  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),
                ),
              )
            ],
          ),
        )
      ],
    ),
  ),
),

【讨论】:

为什么不在这里使用列/行? 有不同的解决方案来达到预期的结果。我的回答是试图解释为什么 OP 提供的解决方案不起作用。

以上是关于颤振位置堆栈小部件在中心的主要内容,如果未能解决你的问题,请参考以下文章

颤振堆栈错误?在堆栈(dartpad 和 web)中存在网络图像时,文本显示在动画小部件上

颤振小部件的最佳定义?

如何在堆栈中垂直或水平居中小部件?

在颤振/飞镖中与图像下的小部件交互

小部件中的颤振相机预览,而不是全屏

未处理的异常:未找到 MediaQuery 小部件 - 颤振 ShowModalButtonSheet