(Flutter) 在屏幕底部对齐水平列表视图(和相关问题)

时间:2021-03-04 05:09:47

标签: android flutter listview flutter-layout flutter-listview

我的应用程序需要一个可以点击项目的水平列表视图。

粗略的布局描述如下

Container
|_ Stack
    |_ (background content)
    |_ Column (overlay, align end vertically)
          |_ Expand (fill up space above)
          |_ ListView (horizontal)
          |_ SizedBox (padding)

问题

当插入这个 ListView(或取消注释)时,Flutter 抛出了以下错误:

======== Exception caught by rendering library =====================================================
The following assertion was thrown during performLayout():
'package:flutter/src/rendering/viewport.dart': Failed assertion: line 1852 pos 16: 'constraints.hasBoundedHeight': is not true.


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=BUG.md

The relevant error-causing widget was: 
  ListView file:///C:/Users/CybeX/CozyUp/cozyup-mobile-flutter/lib/ui/components/ui_component_partner_selector.dart:76:13
When the exception was thrown, this was the stack: 
#2      RenderShrinkWrappingViewport.performLayout (package:flutter/src/rendering/viewport.dart:1852:16)
#3      RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
#4      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:113:14)
#5      RenderObject.layout (package:flutter/src/rendering/object.dart:1777:7)
#6      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:113:14)
...
The following RenderObject was being processed when the exception was fired: RenderShrinkWrappingViewport#400d9 relayoutBoundary=up16 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
...  needs compositing
...  parentData: <none> (can use size)
...  constraints: BoxConstraints(0.0<=w<=395.4, 0.0<=h<=Infinity)
...  size: MISSING
...  axisDirection: right
...  crossAxisDirection: down
...  offset: ScrollPositionWithSingleContext#72596(offset: 0.0, range: null..null, viewport: null, ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#601d0, ScrollDirection.idle)
RenderObject: RenderShrinkWrappingViewport#400d9 relayoutBoundary=up16 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE

我尝试将 ListView 包裹在 Expanded 中,但这按照建议的 here 将其重新居中在屏幕中间。我尝试按照建议的 here 添加扩展顶部,但 Flutter 不喜欢这样。

fwiw,也尝试了 ShrinkWrap(在这里并没有真正期待太多 - 也没有帮助)

MVCE

import 'package:flutter/material.dart';

void main() async {
  runApp(MaterialApp(home: MyApp()));
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    List<String> imgSrc = [
      "https://randomuser.me/api/portraits/women/84.jpg",
          "https://randomuser.me/api/portraits/men/82.jpg",
          "https://randomuser.me/api/portraits/women/11.jpg",
          "https://randomuser.me/api/portraits/women/61.jpg",
          "https://randomuser.me/api/portraits/men/1.jpg",
    ];

    List<Widget> _listviewItems() {
      return imgSrc
          .map((e) => Image.network(e))
          .map((e) => Image(
                image: e.image,
                fit: BoxFit.scaleDown,
                width: 64,
              ))
          .toList();
    }

    Widget w = Container(
        child: Stack(
      children: [
        // Center(
        //   child: cards.first,
        // ),
        Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            Expanded(
                child: ListView(
              padding: const EdgeInsets.all(0.0),
              scrollDirection: Axis.horizontal,
              children: _listviewItems(),
            )),
            SizedBox(
              height: 8,
            )
          ],
        )
      ],
    ));

    return Scaffold(
      body: Container(width: double.infinity, child: w),
    );
  }
}

enter image description here

上图是用 ListView 包裹的 Expanded,即

   Column(
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
        Expanded(
            child: Container()
        ),
        ListView(
          padding: const EdgeInsets.all(0.0),
          scrollDirection: Axis.horizontal,
          children: _listviewItems(),
        ),
        SizedBox(
          height: 8,
        )
      ],
    )

问题:

如何将水平列表视图与屏幕底部对齐以允许水平滚动(如上图所示)?

仅供参考:我添加了 shrinkWrap: true 并将 Column(在堆栈内)包裹在 Extended(如建议的 here)中,导致错误引导我here,这表明相反 - 非常令人沮丧!

2 个答案:

答案 0 :(得分:0)

用容器包裹你的列表视图,并像这样为容器提供高度

Container(
 height:50,
  ListView(
      padding: const EdgeInsets.all(0.0),
      scrollDirection: Axis.horizontal,
      children: _listviewItems(),
    ),
),

答案 1 :(得分:0)

您可以在下面复制粘贴运行2完整代码
解决方案 1:您可以使用 bottomSheet
代码片段

return Scaffold(
      appBar: ...
      body: ...
      bottomSheet: SizedBox(height: 64, child: listview()),
    );

解决方案 2:用 ListViewAlign 包裹 SizedBox
代码片段

Expanded(
        child: Align(
      alignment: Alignment.bottomCenter,
      child: SizedBox(
        height: 64,
        child: ListView(
          padding: const EdgeInsets.all(0.0),
          scrollDirection: Axis.horizontal,
          children: _listviewItems(),
        ),

工作演示

enter image description here

解决方案1的完整代码

import 'package:flutter/material.dart';

void main() async {
  runApp(MaterialApp(home: MyApp()));
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    List<String> imgSrc = [
      "https://randomuser.me/api/portraits/women/84.jpg",
      "https://randomuser.me/api/portraits/men/82.jpg",
      "https://randomuser.me/api/portraits/women/11.jpg",
      "https://randomuser.me/api/portraits/women/61.jpg",
      "https://randomuser.me/api/portraits/men/1.jpg",
      "https://randomuser.me/api/portraits/men/2.jpg",
      "https://randomuser.me/api/portraits/men/3.jpg",
      "https://randomuser.me/api/portraits/men/4.jpg",
      "https://randomuser.me/api/portraits/men/5.jpg",
      "https://randomuser.me/api/portraits/men/6.jpg",
      "https://randomuser.me/api/portraits/men/7.jpg",
    ];

    Widget listview() {
      List<Widget> imgList = imgSrc
          .map((e) => Image.network(e))
          .map((e) => Image(
                image: e.image,
                fit: BoxFit.scaleDown,
                width: 64,
              ))
          .toList();

      return ListView(
        scrollDirection: Axis.horizontal,
        children: imgList,
      );
    }

    return Scaffold(
      appBar: AppBar(title: const Text('AppBar Demo')),
      body: Center(
        child: Container(
            //width: double.infinity,
            child: Text("other content")),
      ),
      bottomSheet: SizedBox(height: 64, child: listview()),
    );
  }
}

解决方案2的完整代码

import 'package:flutter/material.dart';

void main() async {
  runApp(MaterialApp(home: MyApp()));
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    List<String> imgSrc = [
      "https://randomuser.me/api/portraits/women/84.jpg",
      "https://randomuser.me/api/portraits/men/82.jpg",
      "https://randomuser.me/api/portraits/women/11.jpg",
      "https://randomuser.me/api/portraits/women/61.jpg",
      "https://randomuser.me/api/portraits/men/1.jpg",
      "https://randomuser.me/api/portraits/men/2.jpg",
      "https://randomuser.me/api/portraits/men/3.jpg",
      "https://randomuser.me/api/portraits/men/4.jpg",
      "https://randomuser.me/api/portraits/men/5.jpg",
      "https://randomuser.me/api/portraits/men/6.jpg",
      "https://randomuser.me/api/portraits/men/7.jpg",
    ];

    List<Widget> _listviewItems() {
      return imgSrc
          .map((e) => Image.network(e))
          .map((e) => Image(
                image: e.image,
                fit: BoxFit.scaleDown,
                width: 64,
              ))
          .toList();
    }

    Widget w = Container(
        child: Stack(
      children: [
        // Center(
        //   child: cards.first,
        // ),
        Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            Expanded(
                child: Align(
              alignment: Alignment.bottomCenter,
              child: SizedBox(
                height: 64,
                child: ListView(
                  padding: const EdgeInsets.all(0.0),
                  scrollDirection: Axis.horizontal,
                  children: _listviewItems(),
                ),
              ),
            )),
            SizedBox(
              height: 8,
            )
          ],
        )
      ],
    ));

    return Scaffold(
      body: Container(width: double.infinity, child: w),
    );
  }
}
相关问题