繁体   English   中英

Flutter ListView.Builder() 在可滚动列中与其他小部件

[英]Flutter ListView.Builder() in scrollable Column with other widgets

我有一个带有大量不同视图的 TabBarView()。 我希望它们是一个列,顶部有一个 TextField,下面有一个 ListView.Builder(),但是两个小部件应该在同一个可滚动区域(滚动视图)中。 我实现它的方式引发了一些错误:

@override
Widget build(BuildContext context) {
return new Column(
  mainAxisAlignment: MainAxisAlignment.center,
    mainAxisSize: MainAxisSize.max,
    children: <Widget>[
      new Padding(
          padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
          child: new TextField(
            decoration: new InputDecoration(
                hintText: "Type in here!"
            ),
          )
      ),
      new ListView.builder(
          itemCount: _posts.length, itemBuilder: _postBuilder)
    ],
   );
}

错误:

I/flutter (23520): The following assertion was thrown during performResize():
I/flutter (23520): Vertical viewport was given unbounded height.
I/flutter (23520): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter (23520): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter (23520): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter (23520): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter (23520): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter (23520): instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
I/flutter (23520): the height of the viewport to the sum of the heights of its children.

我阅读了有关在扩展区域中堆叠 ListView.builder() 的信息,但它使文本字段有点“粘”,这不是我想要的。 :-)

我也遇到了 CustomScrollView 但没有完全理解如何实现它。

这是解决方案:

SingleChildScrollView(
        physics: ScrollPhysics(),
        child: Column(
          children: <Widget>[
             Text('Hey'),
             ListView.builder(
                physics: NeverScrollableScrollPhysics(),
                shrinkWrap: true,
                itemCount:18,
                itemBuilder: (context,index){
                  return  Text('Some text');
                })
          ],
        ),
      ),

将 ListView 放在Expanded小部件内应该可以解决您的问题:

@override
Widget build(BuildContext context) {
return new Column(
  mainAxisAlignment: MainAxisAlignment.center,
    mainAxisSize: MainAxisSize.max,
    children: <Widget>[
      new Padding(
          padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
          child: new TextField(
            decoration: new InputDecoration(
                hintText: "Type in here!"
            ),
          )
      ),
      new Expanded(child: ListView.builder(
          itemCount: _posts.length, itemBuilder: _postBuilder))
    ],
   );
}

使用SingleChildScrollView允许子小部件滚动

解决方案

SingleChildScrollView(
          child: Column(
            children: <Widget>[
                      ListView.builder(
                      shrinkWrap: true,
                      physics: NeverScrollableScrollPhysics(),

这里使用的两个属性

shrinkWrap: true

只占用它需要的空间(当有更多项目时它仍然会滚动)。

physics: NeverScrollableScrollPhysics()

不允许用户滚动的滚动物理。 意味着只有 Column+SingleChildScrollView 滚动工作。

错误原因:

Column在主轴方向(垂直轴)扩展到最大尺寸, ListView也是如此

解决方案

您需要限制ListView的高度,以便它扩展以匹配Column ,有几种方法可以解决这个问题,我在这里列出了一些:


  1. 如果您想让ListView占用Column内的所有剩余空间,请使用Flexible

     Column( children: <Widget>[ Flexible( child: ListView(...), ) ], )

  1. 如果要将ListView限制为特定height ,可以使用SizedBox

     Column( children: <Widget>[ SizedBox( height: 200, // constrain height child: ListView(), ) ], )

  1. 如果您的ListView很小,您可以尝试shrinkWrap属性。

     Column( children: <Widget>[ ListView( shrinkWrap: true, // use it ) ], )

ListView.Builder() 中使用物理:NeverScrollableScrollPhysics()shrinkWrap: true并享受

使用Expanded小部件进行约束而不会使这些像素溢出,:)

Column(
  children: <Widget>[
    Expanded(
      child: ListView(),
    ),
    Expanded(
      child: ListView(),
    ),
  ],
)
//If you want Listview.builder inside ListView and want to scroll the parent ListView// //whenever the Items in ListView.builder ends or start you can do it like this
       body: ListView(
                  physics: ScrollPhysics(),
                  children: [
                    SizedBox(height: 20),
                    Container( height: 110.0 *5, // *5 to give size to the container //according to items in the ListView.builder. Otherwise will give hasSize Error
                    child:ListView.builder(
                       physics: NeverScrollableScrollPhysics(),
                       scrollDirection: Axis.vertical,
                       itemCount: 5,
                        itemBuilder: (BuildContext context, int indexChild) {
                         return InkWell(child:Container(height:100));}))                
                    ),]),

在我有未来的情况下,我是这样做的:

SingleChildScrollView(
      physics: ScrollPhysics(),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Text("Hey ho let's go!"),
          
          Flexible(
            child: FutureBuilder(
              future: getData(),
              builder: (BuildContext context,
                  AsyncSnapshot<List<Sale>> snapshot) {
                

                if (snapshot.connectionState != ConnectionState.done ||
                    snapshot.hasData == null) {
                  
                    return CircularProgressIndicator();

                } else {
                  data = snapshot.data;
                  return ListView.builder(
                      physics: NeverScrollableScrollPhysics(),
                      shrinkWrap: true,
                      itemBuilder: (BuildContext context, int index) {
                        return dataItemWidget(size, data[index], context);
                      },
                      itemCount: data.length,
                    );
                }
              },
            ),
          ),
        ],
      ),
    ),

只需添加

Column(
mainAxisSize: MainAxisSize.max, //Add this line onyour column
children:[
    SomeWidget(),
    Expanded(child:ListView.builder())
  ]
)

Column不可滚动,这就是为什么顶部的TextField不会滚动而底部的ListView会滚动的原因。

在我看来,解决此问题的最佳方法是将TextField设为ListView的第一项。

所以你不需要一列,你的父小部件是ListView ,它的孩子是TextField后面是你用_postBuilder构建的其余项目。

最好的方法是通过使列子列成为 SingleChildScrollView 然后将相同的 ScrollController 分配给 SingleChildScrollView 和 ListView.builder 来使列可滚动。 这将使文本字段和下面的 ListView 成为可滚动的。

只需在ListView.builder() 中添加物理:NeverScrollableScrollPhysics ()这样您就可以滚动

Listview.builder()方法中添加physics: NeverScrollableScrollPhysics()并且嵌套的Listview将滚动

这是一个有效的解决方案:

class NestedListExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        const SliverToBoxAdapter(
          child: Text('Header'),
        ),
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (ctx, index) {
              return ListTile(title:Text('Item $index'));
            },
          ),
        ),
      ],
    );
  }
}

这是 dartpad 上的预览

您可以将 SliverToBoxAdapter 用于其他子级,因为只有 Slivers 可以是 CustomScrollView 的直接子级。

如果所有列表项的高度相同,那么您可以使用SliverFixedExtentList ,这会更有效,因为每个子项的高度不是即时计算的,但您必须知道确切的像素高度。 您还可以使用SliverPrototypeExtentList ,在其中提供列表中的第一项(原型),所有其他子项将使用原型的高度,因此您无需知道以像素为单位的确切高度。

  body:  SingleChildScrollView(
    physics: ScrollPhysics(),
    child: Column(
          children: [
            getFiltersOnHomePage(),

            SizedBox(
              child: StreamBuilder(
                stream: FirebaseFirestore.instance.collection('posts').snapshots(),
                builder: (context,
                    AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return const Center(
                      child: CircularProgressIndicator(),
                    );
                  }
                  return ListView.builder(
                      physics: NeverScrollableScrollPhysics(),
                      shrinkWrap: true,
                      itemCount: snapshot.data!.docs.length,
                      itemBuilder: (ctx, index) => Container(
                            margin: EdgeInsets.symmetric(
                              horizontal: width > webScreenSize ? width * 0.3 : 0,
                              vertical: width > webScreenSize ? 15 : 0,
                            ),
                            child: PostCard(
                              snap: snapshot.data!.docs[index].data(),
                            ),
                          ));
                },
              ),
            ),
           

          ],
        ),
  ),[enter image description here][1]***You will be able to scroll through the page by using Expanded Widget

Blockquote 使用这个你可以滚动整个页面。 此页面在可滚动列中包含一行和一个列表视图构建器。


  1. return Column( children: [ Text("Popular Category"), Expanded ( child: ListView.builder( enter code here shrinkWrap: false, scrollDirection: Axis.horizo​​ntal, itemCount: 3, itemBuilder: (context, index) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("hello"), ], ); }), ) ], );

在我的例子中,我添加了一个颜色透明且高度高达 270 的 Container 来解决这个问题。

Column(
  children: <Widget>[
    ListView(
      shrinkWrap: true, // use it
    ),
    Container(
      color: Colors.transparent,
      height: 270.0,
    ),
  ],
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM