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
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"),
),
),
);
},
));
}
}
Thanks for the answers. This one helped me a bit more:
flutter ListView children size
I ended up with code like this:
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;
}
And then use those like this:
return Container(
margin: EdgeInsets.only(right:rightCut, left: leftCut),
padding:
EdgeInsets.only(left: (_fullList[index].level * 30.0)),
child: Card(
child: ListTile(
...
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(
..
Add the scrollDirection attribute to your listView like this;
scrollDirection: Axis.horizontal
I know this is a bit late but this may be the easiest solution. I don't know if this is a good practice or not (you may comment below if it is not).
What I did is I wrapped the message (I mean the widget that contains the message) into a row and added a Spacer()
widget at first or in last depending upon whether the message is on right side or on left
So the code might look something like (The code below is for message on the left side)
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(),
]
)