【问题标题】:how to create a row of scrollable text boxes or widgets in flutter inside a ListView?如何在 ListView 内颤动中创建一行可滚动的文本框或小部件?
【发布时间】:2018-02-23 15:43:47
【问题描述】:

1. 请有人告诉我如何在 ListView 中创建一行可左右滚动的文本框。我可以看到我正在尝试在有限宽度的 ListView 内定义无限宽度。但是,无法找到任何解决方法。

如果简单地在customscrollview 中注释scrolldirection 属性(即,将scrolldirection 更改为垂直),下面提到的代码绝对可以正常工作。但是,我正在寻找水平滚动。 我试图解决这个问题,但没有运气。

有人可以帮忙,让我知道我哪里做错了。

  1. 另外,我们如何像在 Android 中那样在 Flutter 中创建或扩展布局? 我已经包含了我正在创建的布局的屏幕截图以供参考:

我已经发布了下面的代码来重现同样的错误;

问候, 鲯鳅

  import 'package:flutter/material.dart';
  import 'package:flutter/rendering.dart';
   import 'package:flutter/widgets.dart';
       void main(){
       runApp(new AddNewBlock());
       }

 class AddNewBlock extends StatefulWidget{

@override
State<StatefulWidget> createState() {
return new _AddNewBlockState();
    }
  }

   class _AddNewBlockState extends State<AddNewBlock>{


    @override
   Widget build(BuildContext context) {
   return new MaterialApp(
            title: 'Add New Block',
  debugShowCheckedModeBanner: false,

  home: new Scaffold(

    body: new ListView(
      shrinkWrap: true,

      children: <Widget>[
        new Container(
          margin: const EdgeInsets.only(
            left: 16.0,top: 24.0, bottom: 8.0,
          ),
          child: new Text(
            'Add New Block',
          style: new TextStyle(
            fontSize: 18.0,
            fontWeight: FontWeight.bold,
            color: Colors.teal[300],
    ),
          ),
        ),
        new Container(
          margin: const EdgeInsets.only(left: 16.0, top: 16.0, bottom: 8.0),
          child: new Text ('Block Name'),
        ),

        new Container(
          margin: const EdgeInsets.fromLTRB(16.0, 8.0, 0.0, 8.0),
          child: new Text ('Block A1',
          style: new TextStyle(
            fontSize: 16.0,
            fontWeight: FontWeight.bold
          ),),
        ),
        new Divider(color: Colors.grey,),
        new Container(
          margin: const EdgeInsets.only(left: 16.0, top: 8.0,bottom: 8.0),
          child: new Text('NO. OF FLOORS',
          style: new TextStyle(
            fontSize: 12.0,
          ),
          ),
        ),



       new Container(
                    child: new Row(
                      children: <Widget>[
                        new Flexible(
                          child: new CustomScrollView(
                            shrinkWrap: true,
                            scrollDirection: Axis.horizontal,
                            slivers: <Widget>[
                          new SliverPadding(
                          padding: const EdgeInsets.all(20.0),
                          sliver: new SliverList(
                            delegate: new SliverChildListDelegate(
                              <Widget>[
                                const Text('this'),
                                const Text('is'),
                                const Text('scroll'),
                                const Text('view'),
                                const Text('inside'),
                                const Text('list'),
                                const Text('view'),
                                const Text('in'),
                                const Text('horizontal'),
                                const Text('direction')
                              ],
                            ),
                          ),
                        ),
                      ],
                          ),
                        ),
                      ],
                    ),
                  ),





      ],

    ),
  ),


  );
   }
}

【问题讨论】:

  • 我想将项目放入新行,我应该使用哪个小部件?

标签: dart flutter


【解决方案1】:

我已经设法通过使用ListView.builder() 来做到这一点

这里是完整的代码:

import 'package:flutter/material.dart';


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

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new _MyAppState();
  }
}

class _MyAppState extends State<MyApp> {

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("Scroll on the Horizon"),
          centerTitle: true,
        ),
        body: new ListView.builder(
          scrollDirection: Axis.horizontal,
          itemBuilder: (BuildContext context, int index) {
            return new Row(
              children: <Widget>[
                new Text("Let ", style: new TextStyle(color: Colors.blue),),
                new Text("me ", style: new TextStyle(color: Colors.red)),
                new Text("scroll ", style: new TextStyle(color: Colors.green)),
                new Text("horizontally ",
                    style: new TextStyle(color: Colors.orange)),
                new Text("Let ", style: new TextStyle(color: Colors.blue),),
                new Text("me ", style: new TextStyle(color: Colors.red)),
                new Text("scroll ", style: new TextStyle(color: Colors.green)),
                new Text("horizontally ",
                    style: new TextStyle(color: Colors.orange)),
                new Text("Let ", style: new TextStyle(color: Colors.blue),),
                new Text("me ", style: new TextStyle(color: Colors.red)),
                new Text("scroll ", style: new TextStyle(color: Colors.green)),
                new Text("horizontally ",
                    style: new TextStyle(color: Colors.orange)),
                new Text("Let ", style: new TextStyle(color: Colors.blue),),
                new Text("me ", style: new TextStyle(color: Colors.red)),
                new Text("scroll ", style: new TextStyle(color: Colors.green)),
                new Text("horizontally ",
                    style: new TextStyle(color: Colors.orange)),

              ],

            );
          },


        ));
  }

}

不要忘记将scrollDirection 属性设置为Axis.horizontal,因为它默认为vertical 值。

【讨论】:

  • 嗨@aziza 非常感谢您的回复。但是如您所见,该解决方案对我不起作用,我需要将此滚动行嵌入到 ListView 中,并且滚动方向为垂直。如果您知道如何实现此功能,请告诉我。
  • 啊哈,我觉得我们这里应该看的是NestedScrollView,我以后自己试试看。
【解决方案2】:

我认为这很简单,只要您在水平ListView 上放置一个固定高度的容器即可。但也许我不明白你的问题。如果这不起作用,请发布您的代码和您收到的错误消息。

import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';
import 'dart:collection';

void main() {
  runApp(new MaterialApp(home: new DemoApp()));
}

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text('Nested ListView Example')),
      body: new Center(
        child: new ListView(
          children: <Widget>[
            new Container(
              height: 80.0,
              child: new ListView(
                scrollDirection: Axis.horizontal,
                children: new List.generate(10, (int index) {
                  return new Card(
                    color: Colors.blue[index * 100],
                    child: new Container(
                      width: 50.0,
                      height: 50.0,
                      child: new Text("$index"),
                    ),
                  );
                }),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

【讨论】:

  • 我认为这正是 OP 正在寻找的,我认为问题在于我们认为水平 ListView 必须包装 Row 小部件(将 children 放置在水平顺序),因此出现错误hasSize!=true
  • 非常感谢您的回复@Collin Jackson。这解决了我的问题,我缺少的唯一技巧是指定容器的高度。感谢大家提出宝贵的建议。
  • 是的,你是对的@aziza,我们从未指定容器的高度,这是导致问题的原因。但是,再次感谢 Collin Jackson 回复我们。
  • 我们怎样才能分别定位每个项目以具有不同的文本?
【解决方案3】:

我这样做是为了让我的 Row 小部件可滚动:

Text("Debilidades",
    style: TextStyle(fontWeight: FontWeight.bold)),
SingleChildScrollView(
  scrollDirection: Axis.horizontal,
  padding: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
  child: Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: pokemon.weaknesses == null
          ? <Widget>[
              Text(
                "No tiene debilidades",
                style: TextStyle(color: Colors.grey),
              )
            ]
          : pokemon.weaknesses
              .map((weakness) => FilterChip(
                  backgroundColor: Colors.red,
                  label: Text(
                    weakness,
                    style: TextStyle(color: Colors.white),
                  ),

                  onSelected: (b) {}))
              .toList()),
),

【讨论】:

  • 天哪,这么容易……! :D
【解决方案4】:

你可以使用:

@override
Widget build(BuildContext context) {
  return Column(
    children: <Widget>[
      SizedBox( // Horizontal ListView
        height: 100,
        child: ListView.builder(
          itemCount: 20,
          scrollDirection: Axis.horizontal,
          itemBuilder: (context, index) {
            return Container(
              width: 100,
              alignment: Alignment.center,
              color: Colors.blue[(index % 9) * 100],
              child: Text(index.toString()),
            );
          },
        ),
      ),
      SizedBox( // Vertical ListView
        height: 200,
        child: ListView.builder(
          itemCount: 20,
          itemBuilder: (context, index) {
            return Container(
              width: 50,
              height: 50,
              alignment: Alignment.center,
              color: Colors.orange[(index % 9) * 100],
              child: Text(index.toString()),
            );
          },
        ),
      ),
    ],
  );
}

注意:为简单起见,我没有在单个小部件中重构两个 ListView

输出

【讨论】:

  • 哪个小部件可以让我将项目转移到新行?
【解决方案5】:

您可能想要创建嵌套列表视图

为了尝试这个示例,您只需将以下代码复制粘贴到新创建的 Flutter 项目的 main.dart 文件中即可。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final title = "Nested ListView List";

    List<Choice> choices = const <Choice>[
      const Choice(
          title: 'MacBook Pro',
          date: '1 June 2019',
          description:
          'MacBook Pro (sometimes abbreviated as MBP) is a line of Macintosh portable computers introduced in January 2006 by Apple Inc.',
          imglink:
          'https://images.unsplash.com/photo-1517694712202-14dd9538aa97?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60'),
      const Choice(
          title: 'MacBook Air',
          date: '1 June 2016',
          description:
          'MacBook Air is a line of laptop computers developed and manufactured by Apple Inc. It consists of a full-size keyboard, a machined aluminum case, and a thin light structure.',
          imglink:
          'https://images.unsplash.com/photo-1499673610122-01c7122c5dcb?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60'),
      const Choice(
          title: 'iMac',
          date: '1 June 2019',
          description:
          'iMac is a family of all-in-one Macintosh desktop computers designed and built by Apple Inc. It has been the primary part of Apple consumer desktop offerings since its debut in August 1998, and has evolved through seven distinct forms.',
          imglink:
          'https://images.unsplash.com/photo-1517059224940-d4af9eec41b7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60'),
      const Choice(
          title: 'Mac Mini',
          date: '1 June 2017',
          description:
          'Mac mini (branded with lowercase "mini") is a desktop computer made by Apple Inc. One of four desktop computers in the current Macintosh lineup, along with the iMac, Mac Pro, and iMac Pro, it uses many components usually featured in laptops to achieve its small size.',
          imglink:
          'https://www.apple.com/v/mac-mini/f/images/shared/og_image__4mdtjbfhcduu_large.png?201904170831'),
      const Choice(
          title: 'Mac Pro',
          date: '1 June 2018',
          description:
          'Mac Pro is a series of workstation and server computer cases designed, manufactured and sold by Apple Inc. since 2006. The Mac Pro, in most configurations and in terms of speed and performance, is the most powerful computer that Apple offers.',
          imglink:
          'https://i0.wp.com/9to5mac.com/wp-content/uploads/sites/6/2017/01/mac-pro-2-concept-image.png?resize=1000%2C500&quality=82&strip=all&ssl=1'),
    ];

    return MaterialApp(
        title: title,
        home: Scaffold(
            appBar: AppBar(
              title: Text(title),
            ),
            body:
            ListView(
                children: [
                  Container(
                    height: 300.0,
                    child: ListView(
                        scrollDirection: Axis.horizontal,
                        shrinkWrap: true,
                        padding: const EdgeInsets.all(20.0),
                        children: List.generate(choices.length, (index) {
                          return Center(
                            child: ChoiceCard(
                                choice: choices[index], item: choices[index]),
                          );
                        })),
                  ),
                  Container(
                    height: 300.0,

                    child: ListView(
                        scrollDirection: Axis.horizontal,
                        shrinkWrap: true,
                        padding: const EdgeInsets.all(20.0),
                        children: List.generate(choices.length, (index) {
                          return Center(
                            child: ChoiceCard(
                                choice: choices[index], item: choices[index]),
                          );
                        })),
                  ),
                  Container(
                    height: 300.0,

                    child: ListView(
                        scrollDirection: Axis.horizontal,
                        shrinkWrap: true,
                        padding: const EdgeInsets.all(20.0),
                        children: List.generate(choices.length, (index) {
                          return Center(
                            child: ChoiceCard(
                                choice: choices[index], item: choices[index]),
                          );
                        })),
                  ),
                ])));
  }
}

class Choice {
  final String title;
  final String date;
  final String description;
  final String imglink;

  const Choice({this.title, this.date, this.description, this.imglink});
}

class ChoiceCard extends StatelessWidget {
  const ChoiceCard(
      {Key key,
        this.choice,
        this.onTap,
        @required this.item,
        this.selected: false})
      : super(key: key);

  final Choice choice;
  final VoidCallback onTap;
  final Choice item;
  final bool selected;

  @override
  Widget build(BuildContext context) {
    TextStyle textStyle = Theme.of(context).textTheme.display1;
    if (selected)
      textStyle = textStyle.copyWith(color: Colors.lightGreenAccent[400]);
    return Card(
        color: Colors.white,
        child: Column(
          children: <Widget>[
            new Expanded(
                child: Container(
                  width: 260.0,
                  height: 260.0,
                  child: Image.network(choice.imglink),
                )),
            new Container(
              width: 260.0,
              padding: const EdgeInsets.all(10.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text(choice.title, style: Theme.of(context).textTheme.title),
                  Text(choice.date,
                      style: TextStyle(color: Colors.black.withOpacity(0.5))),
                  Text(choice.description),
                ],
              ),
            )
          ],
          crossAxisAlignment: CrossAxisAlignment.start,
        ));
  }
}

基于:Nested ListView

【讨论】:

    【解决方案6】:

    对于要滚动的行/列,您只需使用SingleChildScrollView 功能并根据需要提及方向。

    SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        child: Row(
            children: [
                //provide all the things u want to horizontally scroll here
            ]
        ),
    );
    

    【讨论】:

      【解决方案7】:

      我使用一个带有水平滚动方向的 SingleChildScrollView 包裹的 Row 小部件来实现这一点,然后,我用另一行包裹了我的行小部件,以便添加一个大小合适的框小部件以使这些小部件之间保持间距。

      【讨论】:

        【解决方案8】:

        在垂直 ListView 中显示水平 ListView 有多种方式

        1. 将行小部件与 SingleChildScrollView 一起使用
        SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: Row(
            children: List.generate(20, (x) => _listItem(x.toString()))
              .toList())),
        

        或者,如果你有一个 List,那么你可以映射它并渲染它来代替 List.generate。下面的示例假设 UserModel 具有属性“firstName”。

        List<UserModel> _list;
        SingleChildScrollView(
           scrollDirection: Axis.horizontal,
           child: Row(
             children: _list.map((e) => _listItem(e.firstName)).toList())),
        
        1. 使用水平 ListView.builder
        Container(
          height:50,// requires a finite vertical height  
          child: ListView.builder(
            itemCount: 50,
            scrollDirection: Axis.horizontal,
            itemBuilder: (_, index) => _listItem(index.toString())),
        ),
        
        1. 使用水平 ListView
        ConstrainedBox(
          constraints: BoxConstraints(maxHeight: 50), // requires vertical bounded height
          child: ListView(
            scrollDirection: Axis.horizontal,
            children: List.generate(20, (x) => _listItem(x.toString()))
              .toList()),
        ),
        

        【讨论】:

          猜你喜欢
          • 2019-05-23
          • 2020-09-05
          • 2018-11-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多