扑。如何使子部件超越其父部件?

Kon*_*tin 6 flutter flutter-layout

我需要制作一个底部栏“购物车”图标并显示它拥有的许多商品。问题是我无法将数字标签放置得足够高。它被它的父约束所剪裁。截图证明了这一点

\n\n

在此输入图像描述

\n\n

按钮本身是一个 Column 小部件,其顶部有 Frare 动画“波浪”演员,其下方有一个堆栈(绿线下方)\n如果将标签向上移动,我会得到以下结果:

\n\n

在此输入图像描述

\n\n

标签本身被剪掉,波浪不知何故消失了。\n我尝试将堆栈包装在 LimitedBox、OverflowBox、SizedBox 中,但都没有解决问题。

\n\n

这是我想要的(理想情况下):

\n\n

在此输入图像描述

\n\n

让父级保留其原始位置和大小,但显示部分超出其的子级

\n\n

以下是按钮类的完整代码(计数器是在 _getCounter() 方法中创建的):

\n\n
class BottomBarButton extends StatefulWidget {\n\n  BottomBarMenuItemModel itemModel;\n  final double barHeight;\n\n\n  BottomBarButton(this.itemModel, this.barHeight);\n\n  @override\n  _BottomBarButtonState createState() => _BottomBarButtonState();\n}\n\nclass _BottomBarButtonState extends State<BottomBarButton> with SingleTickerProviderStateMixin {\n\n  AnimationController _scaleController;\n  Animation<double> _scaleTween;\n  Animation<Color> _colorTween;\n  Animation<Color> _reversedColorTween;\n  StreamSubscription<String> _streamSubscription;\n  StreamSubscription<String> _counterSubscription;\n  String _inactiveAnimation = \'idle\';\n\n  @override\n  void initState() {\n    _streamSubscription = Dispatch().onChangeBottomBar.stream.listen((menuId) {\n      if (widget.itemModel.id == menuId) {\n        return;\n      }\n      setState(() {});\n    });\n\n    _scaleController = AnimationController(\n        vsync: this,\n        duration: const Duration(milliseconds: 250)\n    );\n    _scaleTween = Tween(begin: 1.0, end: 1.2).animate(\n        CurvedAnimation(\n            parent: _scaleController,\n            curve: Curves.bounceInOut\n        )\n    );\n    _colorTween = ColorTween(begin: pizzaBottomBarIconNormalColor, end: pizzaYellow).animate(\n        CurvedAnimation(parent: _scaleController, curve: Curves.bounceInOut)\n    );\n    _reversedColorTween = ColorTween(begin: pizzaYellow, end: pizzaBottomBarIconNormalColor).animate(\n        CurvedAnimation(parent: _scaleController, curve: Curves.bounceInOut)\n    );\n    DataStore().onCartDataChange.stream.listen((newCounter) {\n      setState(() {});\n    });\n\n    super.initState();\n  }\n  @override\n  void dispose() {\n    _scaleController?.dispose();\n    _streamSubscription.cancel();\n    _counterSubscription.cancel();\n    super.dispose();\n  }\n\n  Widget _getCounter() {\n    if (widget.itemModel.id == Dispatch.CartMenu) {\n      var itemsInCart = DataStore().cartData.length;\n      if (itemsInCart > 0) {\n        return AnimatedBuilder(\n          animation: _scaleTween,\n          builder: (c, w) {\n            return Positioned(\n              right: 25 / _scaleTween.value,\n              top: -15 + (20 / _scaleTween.value),\n              child: AnimatedBuilder(\n                animation: _colorTween,\n                builder: (c, w) {\n                  return Container(\n                    width: 20,\n                    height: 20,\n                    decoration: BoxDecoration(\n                      shape: BoxShape.circle,\n                      color: _reversedColorTween.value,\n                    ),\n                    child: Text(\n                      itemsInCart.toString(),\n                      textAlign: TextAlign.center,\n                      style: TextStyle(\n                        color: pizzaBottomBarColor,\n                        fontFamily: "OpenSans",\n                        fontWeight: FontWeight.w500\n                      ),\n                    ),\n                  );\n                },\n              ),\n            );\n          },\n        );\n      }\n    }\n    return Container();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    widget.itemModel.isActive\n      ? _scaleController.forward()\n      : _scaleController.reverse();\n    var animationName = widget.itemModel.isActive ? \'jump_in\' : _inactiveAnimation;\n\n    return Expanded(\n      child: GestureDetector(\n        onTap: () {\n          setState(() {\n            // \xd0\xbd\xd1\x83\xd0\xb6\xd0\xbd\xd0\xbe \xd1\x87\xd1\x82\xd0\xbe\xd0\xb1\xd1\x8b \xd0\xbf\xd1\x80\xd0\xb8 \xd0\xbf\xd0\xb5\xd1\x80\xd0\xb2\xd0\xbe\xd0\xbc \xd1\x80\xd0\xb5\xd0\xbd\xd0\xb4\xd0\xb5\xd1\x80\xd0\xb5 \xd0\xbd\xd0\xb5 \xd0\xb7\xd0\xb0\xd0\xbf\xd1\x83\xd1\x81\xd0\xba\xd0\xb0\xd1\x82\xd1\x8c \xd0\xb2\xd1\x81\xd0\xb5 \xd0\xb0\xd0\xbd\xd0\xb8\xd0\xbc\xd0\xb0\xd1\x86\xd0\xb8\xd0\xb8, \xd0\xb0 \xd0\xb2\xd1\x80\xd1\x83\xd0\xb1\xd0\xb8\xd1\x82\xd1\x8c \xd0\xb0\xd0\xb9\xd0\xb4\xd0\xbb\n            _inactiveAnimation = \'jump_out\';\n            animationName = widget.itemModel.isActive ? \'jump_in\' : _inactiveAnimation;\n            Dispatch().selectMenu(widget.itemModel.id);\n//            print(widget.itemModel.id);\n          });\n        },\n        child: AbsorbPointer(\n          child: Column(\n            children: <Widget>[\n              Stack(\n                children: <Widget>[\n                  Container( // \xd0\xb2\xd1\x8b\xd0\xbf\xd1\x80\xd1\x8b\xd0\xb3\xd0\xb8\xd0\xb2\xd0\xb0\xd1\x8e\xd1\x89\xd0\xb0\xd1\x8f\xd1\x8f \xd0\xb2\xd0\xbe\xd0\xbb\xd0\xbd\xd0\xb0 \xd1\x81\xd0\xb2\xd0\xb5\xd1\x80\xd1\x85\xd1\x83\n                    // \xd0\xb0\xd0\xbd\xd0\xb8\xd0\xbc\xd0\xb0\xd1\x86\xd0\xb8\xd1\x8e \xd0\xbd\xd0\xb0\xd0\xb4\xd0\xbe \xd1\x81\xd0\xb4\xd0\xb2\xd0\xb8\xd0\xbd\xd1\x83\xd1\x82\xd1\x8c \xd0\xbd\xd0\xb0 20 \xd0\xbf\xd0\xb8\xd0\xb5\xd1\x81\xd0\xb5\xd0\xbb\xd0\xb5\xd0\xb9 \xd0\xb2\xd0\xb2\xd0\xb5\xd1\x80\xd1\x85,\n                    // \xd1\x87\xd1\x82\xd0\xbe\xd0\xb1\xd1\x8b \xd1\x83\xd1\x87\xd0\xb5\xd1\x81\xd1\x82\xd1\x8c \xd0\xbf\xd1\x80\xd0\xbe\xd1\x81\xd1\x82\xd1\x80\xd0\xb0\xd0\xbd\xd1\x81\xd1\x82\xd0\xb2\xd0\xbe\n                    // \xd0\xb4\xd0\xbb\xd1\x8f \xd0\xb2\xd1\x8b\xd0\xbf\xd1\x80\xd1\x8b\xd0\xb3\xd0\xb8\xd0\xb2\xd0\xb0\xd1\x8e\xd1\x89\xd0\xb5\xd0\xb9 \xd1\x87\xd0\xb0\xd1\x81\xd1\x82\xd0\xb8\n                    transform: Matrix4.translationValues(0, -20, 0),\n                    alignment: Alignment.bottomCenter,\n                    height: 20,\n                    width: double.infinity,\n                    child: FlareActor(\n                      "assets/anim/bottom_bar_jumpy_button.flr",\n                      alignment: Alignment.bottomCenter,\n                      fit: BoxFit.fitWidth,\n                      animation: animationName,\n                      shouldClip: false,\n                    )\n                  ),\n                  ScaleTransition(\n                    scale: _scaleTween,\n                    child: Container(\n                      // \xd0\xbd\xd0\xb5\xd0\xb0\xd0\xbd\xd0\xb8\xd0\xbc\xd0\xb8\xd1\x80\xd0\xbe\xd0\xb2\xd0\xb0\xd0\xbd\xd0\xbd\xd0\xb0\xd1\x8f \xd0\xb8\xd0\xba\xd0\xbe\xd0\xbd\xd0\xba\xd0\xb0\n                      alignment: Alignment.center,\n                      child: AnimatedBuilder(\n                        animation: _colorTween,\n                        builder: (context, w) {\n                          return Icon(\n                            widget.itemModel.iconData,\n                            size: 20,\n                            color: _colorTween.value,\n                          );\n                        },\n                      ),\n                      height: widget.barHeight - 22,\n                    ),\n                  ),\n                  _getCounter(),\n                ],\n              ),\n              ScaleTransition(\n                // \xd1\x82\xd0\xb5\xd0\xba\xd1\x81\xd1\x82 \xd0\xba\xd0\xbd\xd0\xbe\xd0\xbf\xd0\xbe\xd0\xba \xd0\xb2 \xd0\xbd\xd0\xb8\xd0\xb6\xd0\xbd\xd0\xb5\xd0\xbc \xd0\xb1\xd0\xb0\xd1\x80\xd0\xb5\n                scale: _scaleTween,\n                alignment: FractionalOffset.topCenter, // \xd0\xbf\xd0\xb8\xd0\xb2\xd0\xbe\xd1\x82 \xd0\xbf\xd0\xbe \xd0\xb2\xd0\xb5\xd1\x80\xd1\x85\xd0\xbd\xd0\xb5\xd0\xb9 \xd0\xba\xd1\x80\xd0\xbe\xd0\xbc\xd0\xba\xd0\xb5\n                child: Transform(\n                  transform: Matrix4.translationValues(0, -6, 0),\n                  child: AnimatedBuilder(\n                    animation: _colorTween,\n                    builder: (context, w) {\n                      return Padding(\n                        padding: const EdgeInsets.only(top: 7.0),\n                        child: Text(widget.itemModel.title,\n                          maxLines: 1,\n                          overflow: TextOverflow.ellipsis,\n                          textAlign: TextAlign.start,\n                          style: TextStyle(\n                            fontFamily: \'OpenSans\',\n                            fontWeight: FontWeight.w500,\n                            fontSize: 13,\n                            height: 1,\n                            color: _colorTween.value\n                          ),\n                        ),\n                      );\n                    },\n                  ),\n                ),\n              )\n            ],\n          ),\n        ),\n      ),\n    );\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Cop*_*oad 9

不要使用overflow,它现在已被弃用。clipBehavior代替使用。

Stack(
  clipBehavior: Clip.none, // This is what you need. 
  children: [],
)
Run Code Online (Sandbox Code Playgroud)

  • @Konstantin抱歉,我忽略了内容部分并根据您的问题标题进行了回答。我希望其他人可以从中受益。 (2认同)

Kon*_*tin 1

一些魔法发生了。我已经为此苦苦挣扎了几个小时,但在创建这个主题后几分钟内就想出了一个解决方案。因此,使用 Transform 小部件可以很容易地解决这个问题。像这样:

Widget _getCounter() {
    if (widget.itemModel.id == Dispatch.CartMenu) {
      var itemsInCart = DataStore().cartData.length;
      if (itemsInCart > 0) {
        return AnimatedBuilder(
          animation: _scaleTween,
          builder: (c, w) {
            return Transform(
              transform: Matrix4.translationValues(
                  45 + (5 * _scaleTween.value), 
                  6 - (6 * _scaleTween.value), 0
              ),
              child: AnimatedBuilder(
                animation: _colorTween,
                builder: (c, w) {
                  return Container(
                    width: 20,
                    height: 20,
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      color: _reversedColorTween.value,
                    ),
                    child: Text(
                      itemsInCart.toString(),
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        color: pizzaBottomBarColor,
                        fontFamily: "OpenSans",
                        fontWeight: FontWeight.w500
                      ),
                    ),
                  );
                },
              ),
            );
          },
        );
      }
    }
    return Container();
  }
Run Code Online (Sandbox Code Playgroud)