ListView中的所有内容都会扩展到屏幕宽度,我能改变这个吗?

39

我正在设计一个聊天界面的应用程序,为了让它可以滚动,我把所有的聊天消息都放在了一个列表视图中。但是,我放在列表视图中的任何东西都会水平扩展,以匹配列表视图小部件所具有的屏幕宽度。我能关闭这个功能吗?这样我就可以把我的聊天信息排成一行,另一行聊天信息排成另一行,就像 WhatsApp 一样。只要我能滚动,除了 ListView 解决方案之外的任何解决方案都可以接受。

enter image description here

目前是这个样子。

enter image description here

这是我当前页面的代码。我真的希望有人能帮助我解决这个问题。

import 'package:flutter/material.dart';
//import '../../Library/Library.dart';
//import '../../Ui/ChatMessage.dart';

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

class ChatScreenState extends State<ChatScreen> {

    bool overlayShouldBeVisible = false;

    @override
    Widget build(BuildContext context) {
        return new Stack(
            fit: StackFit.expand,
            children: <Widget>[
                new Scaffold(
                    appBar: new AppBar(
                        title: new Text(
                            'Chatroom name',
                            style: new TextStyle(
                                color: Colors.black,
                            ),
                        ),
                        centerTitle: true,
                        backgroundColor: Colors.white,
                        elevation: 0.0,
                    ),
                    body: new Column(
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: <Widget>[
                            new Expanded(
                                child: new Container(
                                    decoration: new BoxDecoration(
                                        //image: new DecorationImage(image: new AssetImage('assets/backgroundChat.jpg',),fit: BoxFit.cover)
                                    ),
                                    child: new ListView(
                                        children: <Widget>[
                                            new Text('Test'),
                                            new Card(
                                                color: Colors.green,
                                                child: new Padding(
                                                    padding: new EdgeInsets.all(7.0),
                                                    child: new Column(
                                                        crossAxisAlignment: CrossAxisAlignment.end,
                                                        children: <Widget>[
                                                            new Text('Message'),
                                                            new Text('17:00'),
                                                        ],
                                                    ),
                                                ),
                                            ),
                                            new Card(
                                                color: Colors.green,
                                                child: new Padding(
                                                    padding: new EdgeInsets.all(7.0),
                                                    child: new Column(
                                                        crossAxisAlignment: CrossAxisAlignment.end,
                                                        children: <Widget>[
                                                            new Text('Message'),
                                                            new Text('17:00'),
                                                        ],
                                                    ),
                                                ),
                                            ),
                                        ],
                                    ),
                                ),
                            ),
                            new Container(
                                height: 50.0,
                                color: Colors.white,
                                child: new Row(
                                    crossAxisAlignment: CrossAxisAlignment.stretch,
                                    children: <Widget>[
                                        new Expanded(
                                            child: new Padding(
                                                padding: new EdgeInsets.only(left: 20.0),
                                                child: new TextField(),
                                            ),
                                        ),
                                        new Material(
                                            color: Colors.white,
                                            child: new InkWell(
                                                child: new Padding(
                                                    padding: new EdgeInsets.symmetric(horizontal: 20.0),
                                                    child: new Icon(
                                                        Icons.send,
                                                        color: Colors.blue,
                                                    ),
                                                ),
                                                onTap: () => print('send'),
                                            ),
                                        ),
                                    ],
                                ),
                            ),
                        ],
                    ),
                ),
                //overlayShouldBeVisible == true ? new JsonLoader(): new Container(),
                //Library.debugMode ? new DebugOverlay(): new Container(),
            ],
        );
    }
}

是的,我希望ListView占用所有可用的(垂直)空间。除了使用expanded之外,还有其他方法吗? - Kevin Walter
你是什么意思? - Kevin Walter
好的!谢谢 :) - Kevin Walter
4个回答

56
你可以使用 Align widget 来将其子元素在其父级内对齐。
只需在 Align 中包装列表节点(Card 实例)。
 import 'package:flutter/material.dart';
//import '../../Library/Library.dart';
//import '../../Ui/ChatMessage.dart';

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

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

class ChatScreenState extends State<ChatScreen> {
  bool overlayShouldBeVisible = false;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(body: new ListView.builder(
      itemBuilder: (context, index) {
        return new Align(
          alignment: index.isEven ? Alignment.centerLeft : Alignment.centerRight,
          child: new Card(
            child: new Padding(
              padding: const EdgeInsets.all(8.0),
              child: new Text("Hello World $index"),
            ),
          ),
        );
      },
    ));
  }
}

1
还有一个非常好的解决方案!看起来所有的问题都在于将卡片放置在Align或Row中,以防止其宽度达到100%!谢谢! - Kevin Walter
3
行(Row)不是个好主意,对于单个子元素的对齐,请使用Align。对于多个子元素,请使用行(Row)。 - Rémi Rousselet
1
你只需要使用Wrap()小部件包装你不想占据整个屏幕宽度的子小部件即可。 - Mahamat

15

我对你的代码进行了一些重构,以下是结果:

基本上,我为消息类型(发送或接收)保留了一个标志,并相应地对齐了消息卡片

请注意,我没有时间审查代码,但我注意到很多不必要的嵌套,所以您可能需要稍微修改布局

enter image description here

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

class ChatMessage extends StatelessWidget {
  String type;
  ChatMessage({this.type});
  @override
  Widget build(BuildContext context) {
    return new Row(
      mainAxisAlignment:
          this.type == "sent" ? MainAxisAlignment.end : MainAxisAlignment.start,
      children: <Widget>[
        new Card(
          color: Colors.green,
          child: new Padding(
            padding: new EdgeInsets.all(7.0),
            child: new Column(
              crossAxisAlignment: CrossAxisAlignment.end,
              children: <Widget>[
                new Text('Message'),
                new Text('17:00'),
              ],
            ),
          ),
        ),
      ],
    );
  }
}

class ChatScreenState extends State<ChatScreen> {
  bool overlayShouldBeVisible = false;

  @override
  Widget build(BuildContext context) {
    return new Stack(
      fit: StackFit.expand,
      children: <Widget>[
        new Scaffold(
          appBar: new AppBar(
            title: new Text(
              'Chatroom name',
              style: new TextStyle(
                color: Colors.black,
              ),
            ),
            centerTitle: true,
            backgroundColor: Colors.white,
            elevation: 0.0,
          ),
          body: new Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              new Expanded(
                child: new Container(
                  decoration: new BoxDecoration(
                      //image: new DecorationImage(image: new AssetImage('assets/backgroundChat.jpg',),fit: BoxFit.cover)
                      ),
                  child: new ListView(
                    children: <Widget>[
                      new ChatMessage(
                        type: "sent",
                      ),
                      new ChatMessage(
                        type: "sent",
                      ),
                      new ChatMessage(
                        type: "received",
                      ),
                      new ChatMessage(
                        type: "sent",
                      ),
                      new ChatMessage(
                        type: "received",
                      ),
                      new ChatMessage(
                        type: "received",
                      ),
                    ],
                  ),
                ),
              ),
              new Container(
                height: 50.0,
                color: Colors.white,
                child: new Row(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: <Widget>[
                    new Expanded(
                      child: new Padding(
                        padding: new EdgeInsets.only(left: 20.0),
                        child: new TextField(),
                      ),
                    ),
                    new Material(
                      color: Colors.white,
                      child: new InkWell(
                        child: new Padding(
                          padding: new EdgeInsets.symmetric(horizontal: 20.0),
                          child: new Icon(
                            Icons.send,
                            color: Colors.blue,
                          ),
                        ),
                        onTap: () => print('send'),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
        //overlayShouldBeVisible == true ? new JsonLoader(): new Container(),
        //Library.debugMode ? new DebugOverlay(): new Container(),
      ],
    );
  }
}

或者像Rémi建议的那样,您可以直接使用Align而不是Row,如下所示:

return new Align(
      alignment:this.type!="sent"?  FractionalOffset.centerLeft:FractionalOffset.centerRight,
                  child: 
                    new Card(
    ..

哇,非常感谢。让我现在就去看看! - Kevin Walter
1
Align是一个更加直接的解决方案。 - Rémi Rousselet
看代码结构并没有太多改变。是哪一部分导致消息不能占满整个屏幕宽度?只是为了我的知识,以便我知道如何在未来工作。但它的效果非常棒。非常感谢! - Kevin Walter
哦,我想我明白了。是因为你把卡片放在一行里吗? - Kevin Walter
@KevinWalter,这是因为一行的问题。你可能需要检查一下@Rémi的评论,我并没有想到Align,但在这里似乎是更好的解决方案。 - Shady Aziza
是的,我已经实现了Align。它运行得非常好!再次感谢你! - Kevin Walter

2
我知道有点晚了,但这可能是最简单的解决方案。我不知道这是否是一个好的实践方法(如果不是,您可以在下面评论)。
我的做法是将消息(我的意思是包含消息的小部件)包装到一行中,并在消息在右侧还是左侧时首先或最后添加一个Spacer()小部件。
所以代码可能看起来像这样(以下代码是用于左侧的消息):
Row(
children: [
  Card(
    color: Colors.green,
    child: new Padding(
      padding: new EdgeInsets.all(7.0),
      child: new Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        children: <Widget>[
          new Text('Message'),
          new Text('17:00'),
        ],
      ),
    ), 
  )
  Spacer(),
]
)

0

感谢回答。这个对我有一点帮助:

Flutter ListView 子项大小

最终我得到了以下的代码:

  var sizeW = MediaQuery.of(context).size.width;
  var leftCut = 0.0;
  var rightCut = 0.0;
  if (sizeW > WEB_MAX_WIDTH) {
    leftCut = (sizeW - WEB_MAX_WIDTH) / 2;
    rightCut = leftCut;
  }

然后像这样使用它们:

          return Container(
            margin: EdgeInsets.only(right:rightCut, left: leftCut),
              padding:
                  EdgeInsets.only(left: (_fullList[index].level * 30.0)),
              child: Card(
                  child: ListTile(
                ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接