如何使 SingleChildScrollView 中的 Wrap 小部件子级在 Flutter 中扩展到全高?

Posted

技术标签:

【中文标题】如何使 SingleChildScrollView 中的 Wrap 小部件子级在 Flutter 中扩展到全高?【英文标题】:How to make the Wrap widget child inside SingleChildScrollView to expand to full height in Flutter? 【发布时间】:2020-09-06 18:00:56 【问题描述】:

我正在尝试制作一个 UI,其中容器内有一些文本字段,并且有一些图标按钮总是会留在底部。

这是代码最小代码

Center(
  child: Container(
    // width: 1006,
    constraints: BoxConstraints(
      maxWidth: 1006,
      maxHeight: sizingInformation.screenSize.height,
    ),
    margin: EdgeInsets.only(
      left: isMobile ? 0 : 34,
    ),
    child: Flex(
      direction: Axis.vertical,
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      Flex(
      // rest of the widgets
      ),
      Expanded(
        child: Container(
          padding: EdgeInsets.all(isMobile ? 15 : 34),
          margin: EdgeInsets.only(
            top: isMobile ? 15 : 27,
          ),
          constraints: BoxConstraints(
            maxWidth: 1006,
          ),
          height: 750,
          decoration: BoxDecoration(
            color: CARD_DARK_PURPLE,
            borderRadius: BorderRadius.circular(8),
          ),
          child: SingleChildScrollView(
            physics: AlwaysScrollableScrollPhysics(),
            child: Wrap(
              direction: Axis.horizontal,
              children: <Widget>[
                Wrap(
                  direction: Axis.horizontal,
                  children: <Widget>[
                    Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        Text(
                          "Pošiljalac",
                          style: TextStyle(
                            color: WHITE,
                            fontSize: isMobileTablet ? 22 : 24,
                            fontWeight: BOLD,
                          ),
                        ),
                        SizedBox(
                          height: 20,
                        ),
                        _phoneInfo(widget.order.senderPhoneNumber, isMobile),
                        _emailInfo(widget.order.senderEmail, isMobile),
                        _fullNameInfo(widget.order.senderFirstName,
                            widget.order.senderLastName, isMobile, isMobileTablet),
                        _addressInfo(widget.order.senderStreetNumber, isMobile),
                        _zipCodeInfo(widget.order.senderZipCode, isMobile),
                        _cityInfo(widget.order.senderCity, isMobile),
                        SizedBox(
                          height: isDesktopLaptop ? 14 : 0,
                        ),
                        _payeeInfo(isMobile,  isMobileTablet),
                      ],
                    ),
                    SizedBox(
                      width: 34,
                    ),
                    Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        SizedBox(
                          height: isDesktopLaptop ? 482 : 10,
                        ),
                        _weightInfo(isMobile,  isMobileTablet),
                        _noteSmall(isMobile,  isMobileTablet),
                      ],
                    ),
                  ],
                ),
                Container(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    mainAxisAlignment: MainAxisAlignment.end,
                    children: <Widget>[
                      SizedBox(height: 10),
                      Flex(
                        direction: Axis.horizontal,
                        mainAxisAlignment: MainAxisAlignment.end,
                        children: <Widget>[
                          SizedBox(width: 20),
                          Material(
                            color: DIVIDER,
                            shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(30),
                            ),
                            child: Center(
                              child: Ink(
                                decoration: const ShapeDecoration(
                                  color: DIVIDER,
                                  shape: CircleBorder(),
                                ),
                                child: IconButton(
                                  splashColor: DARK_PURPLE.withOpacity(0.3),
                                  icon: Image.asset(
                                    'assets/images/inter-note-icon.png',
                                    width: 20,
                                    height: 24,
                                  ),
                                  onPressed: () 
                                    if (widget.order.operatorNote == "/") 
                                      _dialogs.internNoteDialog(
                                          context,
                                          widget.order.id,
                                          "order",
                                          widget.order.operatorNote);
                                     else 
                                      _dialogs.changeInternNoteDialog(
                                          context,
                                          widget.order.id,
                                          "order",
                                          widget.order.operatorNote);
                                    
                                  ,
                                ),
                              ),
                            ),
                          ),
                          SizedBox(width: 20),
                          Material(
                            color: DIVIDER,
                            shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(30),
                            ),
                            child: Center(
                              child: Ink(
                                decoration: const ShapeDecoration(
                                  color: DIVIDER,
                                  shape: CircleBorder(),
                                ),
                                child: IconButton(
                                  splashColor: DARK_PURPLE.withOpacity(0.3),
                                  icon: Image.asset(
                                    'assets/images/trash-icon.png',
                                    width: 28,
                                    height: 28,
                                  ),
                                  onPressed: () 
                                    _dialogs.deleteOrderDialog(
                                        context, widget.order.id, isMobile);
                                  ,
                                ),
                              ),
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),  
    ),
  ),
)

这是我想要实现的 UI(右侧突出显示的框)

SingleChildScrollView 父级以 Wrap 作为其子级。 SingleChildScrollView 正在占用可用的全高,但 Wrap 没有跨越到全高。我想让Wrap 跨越整个高度,以便图标可以始终保持在底部。

所以,我将它放在Expanded 中,因为我认为它会使其扩展至完整的可用高度。但是我收到了这个错误。

The following assertion was thrown while applying parent data.:
Incorrect use of ParentDataWidget.

The ParentDataWidget Expanded(flex: 1) wants to apply ParentData of type FlexParentData to a RenderObject, which has been set up to accept ParentData of incompatible type ParentData.

Usually, this means that the Expanded widget has the wrong ancestor RenderObjectWidget. Typically, Expanded widgets are placed directly inside Flex widgets.
The offending Expanded is currently placed inside a _SingleChildViewport widget.

The ownership chain for the RenderObject that received the incompatible parent data was:
  Wrap ← Expanded ← _SingleChildViewport ← IgnorePointer-[GlobalKey#01401] ← Semantics ← _PointerListener ← Listener ← _GestureSemantics ← RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#7427b] ← _PointerListener ← ⋯
When the exception was thrown, this was the stack
dart:sdk_internal 4461:11                                                 throw_
packages/flutter/src/widgets/widget_span.dart.lib.js 12339:23             <fn>
packages/flutter/src/widgets/widget_span.dart.lib.js 12355:24             [_updateParentData]
packages/flutter/src/widgets/widget_span.dart.lib.js 12372:61             attachRenderObject
packages/flutter/src/widgets/widget_span.dart.lib.js 12184:12             mount
...
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by widgets library ═══════════════════════════════════
Incorrect use of ParentDataWidget.
════════════════════════════════════════════════════════════════════════════════

因此,Expanded 不是解决此问题的方法。但我不知道还有什么。我是 Flutter 新手,很难理解 Flutter 布局系统。任何帮助都会很棒。感谢您的宝贵时间。

【问题讨论】:

不确定您尝试实现的布局,但如果按钮应始终位于屏幕按钮上,我觉得它们不应位于 SingleChildScrollView 内。 @ZeRj 停留在底部意味着如果有滚动条,它们将出现在底部的文本字段之后,如果没有滚动条,则停留在底部。 您找到解决方案了吗?我也有同样的问题。 【参考方案1】:

如果您将Wrap 小部件设为屏幕大小的容器的子级会怎样?

class MyWidget extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: SingleChildScrollView(
          child: Container(
              height: MediaQuery.of(context).size.height,
              width: MediaQuery.of(context).size.width,
              child: Wrap(
                children: [],
              ))),
    );
  

【讨论】:

感谢您的回复。但这在我的情况下不起作用,因为高度不会是视口的高度。还有其他小部件,所以不能这样做。 @Bhawna 那么您需要使用您拥有的小部件树以及屏幕截图来更新您的 OP,以便更清楚地理解 我已经添加了 UI 的小部件树和屏幕截图。希望对您有所帮助。

以上是关于如何使 SingleChildScrollView 中的 Wrap 小部件子级在 Flutter 中扩展到全高?的主要内容,如果未能解决你的问题,请参考以下文章

如何使 SingleChildScrollView 中的 Wrap 小部件子级在 Flutter 中扩展到全高?

Flutter:如何自动滚动到 SingleChildScrollView 的末尾

TextField 获得焦点时如何滚动到 SingleChildScrollView 的底部?

如何在 Flutter 中自动滚动到 SingleChildScrollView 内的行的位置

如何使用 ListView.separated 使整个屏幕可滚动

如何在 Flutter 中使屏幕可滚动?