如何构建包含 ListView.Builder 的自定义行,以在颤动中构建 ElevatedButton?

Posted

技术标签:

【中文标题】如何构建包含 ListView.Builder 的自定义行,以在颤动中构建 ElevatedButton?【英文标题】:How do I build custom row that has ListView.Builder inside that builds ElevatedButton in flutter? 【发布时间】:2021-10-28 21:14:36 【问题描述】:

我想制作一个屏幕,其中会有一个浮动操作按钮,该按钮调用一个名为 customRow() 的函数,该函数根据我传递给该函数的字符串值动态创建自定义 Row() 小部件。

这是我的 customRow() 代码

customRow(int key, String label, TextInputType type, String widget)

    if(widget == "selection")
      return Row(
        children: [
          Expanded(
            child: TextField(
              onChanged: (val)
                onUpdate(key, val);
              ,
              keyboardType: type,
              decoration: InputDecoration(
                labelText: key.toString(),
                labelStyle: TextStyle(
                  fontSize: 14.0,
                ),
                hintStyle: TextStyle(
                  color: Colors.grey,
                  fontSize: 10.0,
                ),
              ),
              style: TextStyle(fontSize: 14.0),
            ),
          ),
          SizedBox(width: 1.0,),
          SizedBox(
            child: ListView(
              scrollDirection: Axis.horizontal,
              children: [
                Expanded(
                  child: ElevatedButton(
                    onPressed: ()

                    ,
                    child: Text("HELLO"),
                  ),
                ),
                Expanded(
                  child: ElevatedButton(
                    onPressed: ()

                    ,
                    child: Text("HELLO"),
                  ),
                ),
                Expanded(
                  child: ElevatedButton(
                    onPressed: ()

                    ,
                    child: Text("HELLO"),
                  ),
                ),
              ],
            ),
          ),
          TextButton(
            onPressed: ()
              setState(() 
                Map<String, dynamic> tempMap = ;
                for(final element in widgetList) 
                  if(element["id"] == key)
                    tempMap = element;
                    break;
                  
                
                widgetList.remove(tempMap);

                for(final element in customTextValuesList) 
                  if(element["id"] == key)
                    tempMap = element;
                    break;
                  
                

                customTextValuesList.remove(tempMap);
              );

            ,
            child: Icon(Icons.close, color: Colors.red,),
          ),
        ],
      );
    
    else
      return Row(
        children: [
          Expanded(
            child: TextField(
              onChanged: (val)
                onUpdate(key, val);
              ,
              keyboardType: type,
              decoration: InputDecoration(
                labelText: key.toString(),
                labelStyle: TextStyle(
                  fontSize: 14.0,
                ),
                hintStyle: TextStyle(
                  color: Colors.grey,
                  fontSize: 10.0,
                ),
              ),
              style: TextStyle(fontSize: 14.0),
            ),
          ),
          SizedBox(width: 1.0,),
          TextButton(
            onPressed: ()
              setState(() 
                Map<String, dynamic> tempMap = ;
                for(final element in widgetList) 
                  if(element["id"] == key)
                    tempMap = element;
                    break;
                  
                
                widgetList.remove(tempMap);

                for(final element in customTextValuesList) 
                  if(element["id"] == key)
                    tempMap = element;
                    break;
                  
                

                customTextValuesList.remove(tempMap);
              );

            ,
            child: Icon(Icons.close, color: Colors.red,),
          ),
        ],
      );
    
  

因此,当我将小部件参数作为“选择”传递时,它应该能够构建可以水平滚动的高架按钮(因为该行中将有多个按钮)。 “选择” Row() 最后还会有一个“+” TextButton() 以根据需要添加额外的 ElevatedButton()。

现在我想要的是在调用 customRow() 时使用 :selection" 作为参数值来绘制该行。

但是我遇到了类似的错误

======== Exception caught by rendering library =====================================================
The following assertion was thrown during performResize():
Horizontal viewport was given unbounded width.

Viewports expand in the scrolling direction to fill their container. In this case, a horizontal viewport was given an unlimited amount of horizontal space in which to expand. This situation typically happens when a scrollable widget is nested inside another scrollable widget.

If this widget is always nested in a scrollable widget there is no need to use a viewport because there will always be enough horizontal space for the children. In this case, consider using a Row instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size the width of the viewport to the sum of the widths of its children.

The relevant error-causing widget was: 
  ListView file:///D:/Flutter%20Projects/data_entry/lib/AllScreens/voterAddScreen.dart:503:20
When the exception was thrown, this was the stack: 
#0      RenderViewport.computeDryLayout.<anonymous closure> (package:flutter/src/rendering/viewport.dart:1399:15)
#1      RenderViewport.computeDryLayout (package:flutter/src/rendering/viewport.dart:1430:6)
#2      RenderBox.performResize (package:flutter/src/rendering/box.dart:2332:12)
#3      RenderObject.layout (package:flutter/src/rendering/object.dart:1758:9)
#4      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
...
The following RenderObject was being processed when the exception was fired: RenderViewport#fa47f NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
...  needs compositing
...  parentData: <none> (can use size)
...  constraints: BoxConstraints(unconstrained)
...  size: MISSING
...  axisDirection: right
...  crossAxisDirection: down
...  offset: ScrollPositionWithSingleContext#f6d00(offset: 0.0, range: null..null, viewport: null, ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#ef5c4, ScrollDirection.idle)
...  anchor: 0.0
RenderObject: RenderViewport#fa47f NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
  needs compositing
  parentData: <none> (can use size)
  constraints: BoxConstraints(unconstrained)
  size: MISSING
  axisDirection: right
  crossAxisDirection: down
  offset: ScrollPositionWithSingleContext#f6d00(offset: 0.0, range: null..null, viewport: null, ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#ef5c4, ScrollDirection.idle)
  anchor: 0.0
...  center child: RenderSliverPadding#32627 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
...    parentData: paintOffset=Offset(0.0, 0.0)
...    constraints: MISSING
...    geometry: null
...    padding: EdgeInsets.zero
...    textDirection: ltr
...    child: RenderSliverList#e637a NEEDS-LAYOUT NEEDS-PAINT
...      parentData: paintOffset=Offset(0.0, 0.0)
...      constraints: MISSING
...      geometry: null
...      no children current live
====================================================================================================

======== Exception caught by rendering library =====================================================
The following assertion was thrown during performLayout():
RenderBox was not laid out: RenderViewport#fa47f NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1930 pos 12: 'hasSize'


Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.md

The relevant error-causing widget was: 
  ListView file:///D:/Flutter%20Projects/data_entry/lib/AllScreens/voterAddScreen.dart:503:20
When the exception was thrown, this was the stack: 
#2      RenderBox.size (package:flutter/src/rendering/box.dart:1930:12)
#3      RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1450:39)
#4      RenderObject.layout (package:flutter/src/rendering/object.dart:1779:7)
#5      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#6      RenderObject.layout (package:flutter/src/rendering/object.dart:1779:7)
...
The following RenderObject was being processed when the exception was fired: RenderViewport#fa47f NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
...  needs compositing
...  parentData: <none> (can use size)
...  constraints: BoxConstraints(unconstrained)
...  size: MISSING
...  axisDirection: right
...  crossAxisDirection: down
...  offset: ScrollPositionWithSingleContext#f6d00(offset: 0.0, range: null..null, viewport: null, ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#ef5c4, ScrollDirection.idle)
...  anchor: 0.0
RenderObject: RenderViewport#fa47f NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
  needs compositing
  parentData: <none> (can use size)
  constraints: BoxConstraints(unconstrained)
  size: MISSING
  axisDirection: right
  crossAxisDirection: down
  offset: ScrollPositionWithSingleContext#f6d00(offset: 0.0, range: null..null, viewport: null, ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#ef5c4, ScrollDirection.idle)
  anchor: 0.0
...  center child: RenderSliverPadding#32627 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
...    parentData: paintOffset=Offset(0.0, 0.0)
...    constraints: MISSING
...    geometry: null
...    padding: EdgeInsets.zero
...    textDirection: ltr
...    child: RenderSliverList#e637a NEEDS-LAYOUT NEEDS-PAINT
...      parentData: paintOffset=Offset(0.0, 0.0)
...      constraints: MISSING
...      geometry: null
...      no children current live
====================================================================================================

====================================================================================================

我这样调用我的函数

customRow(_counter, "", TextInputType.text, "selection")

我尝试将按钮包装在 Container() 中,将整个东西包装在 Expanded() 中,但没有任何效果。

调用函数的父widget流程是这样的

Scaffold -> Stack -> Container-> Column-> Expanded-> ListView.builder -> customRow(_counter...)

【问题讨论】:

尝试从ListView 中删除Expanded Widget。 调用方法的预期父对象是什么?小部件树是否包含任何可滚动的小部件? 调用函数的widget流程是这样的Scaffold -> Stack ->Container->Column->Expanded->ListView.builder @Nidheesh MT "尝试从 ListView 中删除扩展的小部件"尝试了这个。不工作 尝试将ListView 包裹在Expanded / Flexible 小部件中,并启用ListView 中的shrinkWrap: true 【参考方案1】:

我做到了。整个 customRow() 代码。

customRow(int key, String label, TextInputType type, String widget)

    if(widget == "selection")
      return Column(
        children: [
          Row(
            children: [
              Expanded(
                child: TextField(
                  onChanged: (val)
                    onUpdate(key, val);
                  ,
                  keyboardType: type,
                  decoration: InputDecoration(
                    labelText: key.toString(),
                    labelStyle: TextStyle(
                      fontSize: 14.0,
                    ),
                    hintStyle: TextStyle(
                      color: Colors.grey,
                      fontSize: 10.0,
                    ),
                  ),
                  style: TextStyle(fontSize: 14.0),
                ),
              ),
              SizedBox(width: 40.0,),
              Expanded(
                child: Container(
                  height: 100.0,
                  child: ListView(
                      shrinkWrap: true,
                      scrollDirection: Axis.vertical,
                      children: [
                        Padding(
                          padding: const EdgeInsets.only(bottom: 28.0),
                          child: SizedBox(
                            height: 150.0,
                            child: ListView.builder(
                                shrinkWrap: true,
                                itemCount: 5,
                                itemBuilder: (context, index)
                                  return Column(
                                    children: [
                                      Row(
                                        children: [
                                          ElevatedButton(
                                            onPressed: (),
                                            child: Text("Hello"),
                                          ),
                                          Container(
                                            width: 30.0,
                                            child: TextButton(
                                              onPressed: ()   ,
                                              child: Icon(Icons.close),
                                            ),
                                          ),
                                        ],
                                      ),
                                    ],
                                  );
                                
                            ),
                          ),
                        ),
                      ]
                  ),
                ),
              ),
              Expanded(
                child: TextButton(
                  onPressed: ()
                    setState(() 
                      Map<String, dynamic> tempMap = ;
                      for(final element in widgetList) 
                        if(element["id"] == key)
                          tempMap = element;
                          break;
                        
                      
                      widgetList.remove(tempMap);

                      for(final element in customTextValuesList) 
                        if(element["id"] == key)
                          tempMap = element;
                          break;
                        
                      

                      customTextValuesList.remove(tempMap);
                    );

                  ,
                  child: Icon(Icons.close, color: Colors.red,),
                ),
              ),
            ],
          ),
          DividerWidget(customColor: Colors.blue),
        ],
      );
    
    else
      return Row(
        children: [
          Expanded(
            child: TextField(
              onChanged: (val)
                onUpdate(key, val);
              ,
              keyboardType: type,
              decoration: InputDecoration(
                labelText: key.toString(),
                labelStyle: TextStyle(
                  fontSize: 14.0,
                ),
                hintStyle: TextStyle(
                  color: Colors.grey,
                  fontSize: 10.0,
                ),
              ),
              style: TextStyle(fontSize: 14.0),
            ),
          ),
          SizedBox(width: 1.0,),
          TextButton(
            onPressed: ()
              setState(() 
                Map<String, dynamic> tempMap = ;
                for(final element in widgetList) 
                  if(element["id"] == key)
                    tempMap = element;
                    break;
                  
                
                widgetList.remove(tempMap);

                for(final element in customTextValuesList) 
                  if(element["id"] == key)
                    tempMap = element;
                    break;
                  
                

                customTextValuesList.remove(tempMap);
              );

            ,
            child: Icon(Icons.close, color: Colors.red,),
          ),
        ],
      );
    
  

【讨论】:

以上是关于如何构建包含 ListView.Builder 的自定义行,以在颤动中构建 ElevatedButton?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter ListView.Builder 导致滚动不连贯。如何使滚动平滑?

如何为 ListView.builder 加载数据以从提供者的数据构建

如何在 Flutter 中添加 ListView.builder 的填充顶部?

为啥所有 Slider 小部件在 ListView.builder 中一起移动?

Flutter - 如何访问 ListView.builder 中的一个元素?

颤振 ListView.builder 的无限滚动