In this tutorial you will learn how to create your first chat app in flutter. No database or any form of cloud storage is used, just a dummy a chat app to introduce you to how to create a cah UI in flutter.
Example 1: Hello World Chat App
This is a simple hello world version of chat app creation in language.No database is used.
Step 1: Create Project
Create an empty flutter project.
Step 2: Add Dependencies
No external plugins are used in this example.
Step 3: Write Code
Start by defining your imports, including the material.dart, foundation.dart
as well as the cupertino.dart
:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
Instantiate a Theme data to give us an iOS theme:
final ThemeData iOSTheme = new ThemeData(
primarySwatch: Colors.red,
primaryColor: Colors.grey[400],
primaryColorBrightness: Brightness.dark,
);
Now instantiate another theme for android which will utilize the material
package:
final ThemeData androidTheme = new ThemeData(
primarySwatch: Colors.blue,
accentColor: Colors.green,
);
Create a default user name:
const String defaultUserName = "John Doe";
Create a main function where we will run the MyApp
instance:
void main() => runApp(new MyApp());
Now create the MyApp
as a stateless widget:
class MyApp extends StatelessWidget {
Override the build()
function and set the title as well as theme. If the default target platform is iOS we will apply the iOS theme, otherwise we apply the android theme:
@override
Widget build(BuildContext ctx) {
return new MaterialApp(
title: "Chat Application",
theme: defaultTargetPlatform == TargetPlatform.iOS
? iOSTheme
: androidTheme,
home: new Chat(),
);
}
}
Now create the Chat
class as a Stateful widget:
class Chat extends StatefulWidget {
Override the createState
function and return the ChatWindow
class:
@override
State createState() => new ChatWindow();
}
Now create the ChatWindow
by extending the State
class:
class ChatWindow extends State<Chat> with TickerProviderStateMixin {
Now prepare a list of messages, a TextEditingController and a boolean value as instance fields for this class:
final List<Msg> _messages = <Msg>[];
final TextEditingController _textController = new TextEditingController();
bool _isWriting = false;
Override the build method, set the chat window title, set the appBar as well as the app body:
@override
Widget build(BuildContext ctx) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Chat Application"),
elevation:
Theme.of(ctx).platform == TargetPlatform.iOS ? 0.0 : 6.0,
),
body: new Column(children: <Widget>[
new Flexible(
child: new ListView.builder(
itemBuilder: (_, int index) => _messages[index],
itemCount: _messages.length,
reverse: true,
padding: new EdgeInsets.all(6.0),
)),
new Divider(height: 1.0),
new Container(
child: _buildComposer(),
decoration: new BoxDecoration(color: Theme.of(ctx).cardColor),
),
]),
);
}
Also come and build the chat editing widget. The widget that will be used to type of compose the chat message:
Widget _buildComposer() {
return new IconTheme(
data: new IconThemeData(color: Theme.of(context).accentColor),
child: new Container(
margin: const EdgeInsets.symmetric(horizontal: 9.0),
child: new Row(
children: <Widget>[
new Flexible(
child: new TextField(
controller: _textController,
onChanged: (String txt) {
setState(() {
_isWriting = txt.length > 0;
});
},
onSubmitted: _submitMsg,
decoration:
new InputDecoration.collapsed(hintText: "Enter some text to send a message"),
),
),
new Container(
margin: new EdgeInsets.symmetric(horizontal: 3.0),
child: Theme.of(context).platform == TargetPlatform.iOS
? new CupertinoButton(
child: new Text("Submit"),
onPressed: _isWriting ? () => _submitMsg(_textController.text)
: null
)
: new IconButton(
icon: new Icon(Icons.message),
onPressed: _isWriting
? () => _submitMsg(_textController.text)
: null,
)
),
],
),
decoration: Theme.of(context).platform == TargetPlatform.iOS
? new BoxDecoration(
border:
new Border(top: new BorderSide(color: Colors.brown))) :
null
),
);
}
Then create a function to submit the typed text message:
void _submitMsg(String txt) {
_textController.clear();
setState(() {
_isWriting = false;
});
Msg msg = new Msg(
txt: txt,
animationController: new AnimationController(
vsync: this,
duration: new Duration(milliseconds: 800)
),
);
setState(() {
_messages.insert(0, msg);
});
msg.animationController.forward();
}
Override the dispose
function where we will dispose the animation controller resources:
@override
void dispose() {
for (Msg msg in _messages) {
msg.animationController.dispose();
}
super.dispose();
}
}
Create a model class to represent the chat message:
class Msg extends StatelessWidget {
Msg({this.txt, this.animationController});
final String txt;
final AnimationController animationController;
@override
Widget build(BuildContext ctx) {
return new SizeTransition(
sizeFactor: new CurvedAnimation(
parent: animationController, curve: Curves.easeOut),
axisAlignment: 0.0,
child: new Container(
margin: const EdgeInsets.symmetric(vertical: 8.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
margin: const EdgeInsets.only(right: 18.0),
child: new CircleAvatar(child: new Text(defaultUserName[0])),
),
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(defaultUserName, style: Theme.of(ctx).textTheme.subhead),
new Container(
margin: const EdgeInsets.only(top: 6.0),
child: new Text(txt),
),
],
),
),
],
),
),
);
}
}
Here's the full code:
main.dart
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
final ThemeData iOSTheme = new ThemeData(
primarySwatch: Colors.red,
primaryColor: Colors.grey[400],
primaryColorBrightness: Brightness.dark,
);
final ThemeData androidTheme = new ThemeData(
primarySwatch: Colors.blue,
accentColor: Colors.green,
);
const String defaultUserName = "John Doe";
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext ctx) {
return new MaterialApp(
title: "Chat Application",
theme: defaultTargetPlatform == TargetPlatform.iOS
? iOSTheme
: androidTheme,
home: new Chat(),
);
}
}
class Chat extends StatefulWidget {
@override
State createState() => new ChatWindow();
}
class ChatWindow extends State<Chat> with TickerProviderStateMixin {
final List<Msg> _messages = <Msg>[];
final TextEditingController _textController = new TextEditingController();
bool _isWriting = false;
@override
Widget build(BuildContext ctx) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Chat Application"),
elevation:
Theme.of(ctx).platform == TargetPlatform.iOS ? 0.0 : 6.0,
),
body: new Column(children: <Widget>[
new Flexible(
child: new ListView.builder(
itemBuilder: (_, int index) => _messages[index],
itemCount: _messages.length,
reverse: true,
padding: new EdgeInsets.all(6.0),
)),
new Divider(height: 1.0),
new Container(
child: _buildComposer(),
decoration: new BoxDecoration(color: Theme.of(ctx).cardColor),
),
]),
);
}
Widget _buildComposer() {
return new IconTheme(
data: new IconThemeData(color: Theme.of(context).accentColor),
child: new Container(
margin: const EdgeInsets.symmetric(horizontal: 9.0),
child: new Row(
children: <Widget>[
new Flexible(
child: new TextField(
controller: _textController,
onChanged: (String txt) {
setState(() {
_isWriting = txt.length > 0;
});
},
onSubmitted: _submitMsg,
decoration:
new InputDecoration.collapsed(hintText: "Enter some text to send a message"),
),
),
new Container(
margin: new EdgeInsets.symmetric(horizontal: 3.0),
child: Theme.of(context).platform == TargetPlatform.iOS
? new CupertinoButton(
child: new Text("Submit"),
onPressed: _isWriting ? () => _submitMsg(_textController.text)
: null
)
: new IconButton(
icon: new Icon(Icons.message),
onPressed: _isWriting
? () => _submitMsg(_textController.text)
: null,
)
),
],
),
decoration: Theme.of(context).platform == TargetPlatform.iOS
? new BoxDecoration(
border:
new Border(top: new BorderSide(color: Colors.brown))) :
null
),
);
}
void _submitMsg(String txt) {
_textController.clear();
setState(() {
_isWriting = false;
});
Msg msg = new Msg(
txt: txt,
animationController: new AnimationController(
vsync: this,
duration: new Duration(milliseconds: 800)
),
);
setState(() {
_messages.insert(0, msg);
});
msg.animationController.forward();
}
@override
void dispose() {
for (Msg msg in _messages) {
msg.animationController.dispose();
}
super.dispose();
}
}
class Msg extends StatelessWidget {
Msg({this.txt, this.animationController});
final String txt;
final AnimationController animationController;
@override
Widget build(BuildContext ctx) {
return new SizeTransition(
sizeFactor: new CurvedAnimation(
parent: animationController, curve: Curves.easeOut),
axisAlignment: 0.0,
child: new Container(
margin: const EdgeInsets.symmetric(vertical: 8.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
margin: const EdgeInsets.only(right: 18.0),
child: new CircleAvatar(child: new Text(defaultUserName[0])),
),
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(defaultUserName, style: Theme.of(ctx).textTheme.subhead),
new Container(
margin: const EdgeInsets.only(top: 6.0),
child: new Text(txt),
),
],
),
),
],
),
),
);
}
}
Run
Copy the code into your project or download the code in the reference links below.
Reference
Find the reference links below:
Number | Link |
---|---|
1. | Download code |
2. | Follow code author |