I'm trying to make a design of a chat screen for an app that I'm making. To make it scrollable I placed all the chat messages inside a listview. But everything I place inside a list view expands horizontally to match screenwidth (Width that the Listview widget has). Can I turn this off so I can line out my chat messages to one side and the other chat message to the other side like in whatsapp? Anything other than a ListView solution is also alright as long as I can scroll
This is how it looks now.
This is the code of my current page. I really hope someone can help me with this issue.
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(), ], ); } }
Expandable list view is used to expand or collapse the view in list items In a flutter app. We can easily make our own Expandable ListView using the ExpansionTile widget.
In Flutter, you can use ListView. separated to easily create a list view whose items are separated by separators (or dividers). A separator only appears between two list items and never stands before the first or sits after the last item.
You can make the ListView widget never scrollable by setting physics property to NeverScrollableScrollPhysics().
You can use Align
widget to align it's child inside it's parent.
Simply wrap your list nodes (Card instances) inside a Align
.
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"), ), ), ); }, )); } }
I have done a little bit of refactor on your code an here is the result:
Basically I keep a flag for the type of message (sent or received) and align the message card accordingly
Note I did not have the time to review the code but I noticed a lot of unnecessary nesting so you may want to revise the layout a little bit
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(), ], ); } }
or as Rémi suggested you can just use Align
instead of Row
like so:
return new Align( alignment:this.type!="sent"? FractionalOffset.centerLeft:FractionalOffset.centerRight, child: new Card( ..
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With