在使用Flutter構(gòu)建WhatsApp之前,我們創(chuàng)建了一個帶有選項卡和導(dǎo)航的基本appbar。 今天,我們將使用ListView.builder創(chuàng)建聊天的滾動列表
隨著介紹,這里是我們將要構(gòu)建的截圖
#設(shè)置模型
在我們構(gòu)建List之前,我們將為聊天構(gòu)建模板。 我們首先在lib文件夾中創(chuàng)建一個名為“model”的新文件夾。 在模型文件夾中,創(chuàng)建名為chat_model.dart的文件。 創(chuàng)建文件后,我們現(xiàn)在可以開始構(gòu)建結(jié)構(gòu)了。 我們將從創(chuàng)建ChatModel類開始。
class ChatModel {
}
在這個類中,我們將為我們想要聊天列表的功能創(chuàng)建變量。 WhatsApp通常具有消息的人物,姓名,時間和消息的片段。
創(chuàng)建不同的變量,將它們分配給類型字符串。 它們被設(shè)置為final,因為我們只設(shè)置一次值。 如果您想了解有關(guān)dart中不同變量類型的更多信息,請查看dart變量介紹視頻
class ChatModel {
? final String username;
? final String message;?
? final String time;
? final String avatarurl;
}
很好,聲明了變量,我們現(xiàn)在可以將它傳遞給類的構(gòu)造函數(shù)
這是通過以下代碼行完成的
ChatModel({this.username, this.message, this.time, this.avatarurl});
接下來,我們繼續(xù)創(chuàng)建一個聊天列表。 為此,我們創(chuàng)建一個名為data的變量,它將是List類型。 該列表將是ChatModel類型。 這可確保輸入的數(shù)據(jù)遵循類中列出的格式。
```
List data = [
?new ChatModel(
?? username: 'Nash',
?? message: 'Flutter is soooo cool :)',
?? time: '20:20',
? avatarurl: 'https://pbs.twimg.com/profile_images/945767488087715840/OP_ZIptm_400x400.jpg'
?),
?new ChatModel(
?? username: 'Han Solo',
?? message: 'That is not how the force works ',
? time: '20:20',
? avatarurl: 'https://pbs.twimg.com/profile_images/760249570085314560/yCrkrbl3_400x400.jpg'?
?),
? new ChatModel(
?? username: 'Ethan',
?? message: 'why hello there',
? time: '20:20',
? avatarurl: 'https://s-media-cache-ak0.pinimg.com/originals/d4/c3/ee/d4c3ee93cca0bba877318989b46b39d6.jpg'
?),
? new ChatModel(
?? username: 'Sam',
?? message: 'Lorem ipsum delor sit amet...',
? time: '20:20',
? avatarurl: 'http://clipart-library.com/images/kTMKzGyMc.jpg'
?),
? new ChatModel(
?? username: 'Ava',
?? message: 'AOT is better than JIT ;)',
? time: '20:20',
? avatarurl: 'http://clipart-library.com/images/kTMKzGyMc.jpg'
?),
? new ChatModel(
?? username: 'Jbird',
?? message: 'Stop camping in fortnite Idiot',
? time: '20:20',
? avatarurl: 'https://s-media-cache-ak0.pinimg.com/originals/d4/c3/ee/d4c3ee93cca0bba877318989b46b39d6.jpg'
?),
?? new ChatModel(
?? username: 'Jake',
?? message: 'Flutter is the best!',
? time: '20:20',
? avatarurl: 'http://clipart-library.com/images/kTMKzGyMc.jpg'
?),] ;
```
在上面的代碼中,我們創(chuàng)建了七個帶有消息的用戶。 每個模型都遵循我們創(chuàng)建的格式。 您可以編輯此項以包含任意數(shù)量的用戶。 使用創(chuàng)建聊天的模板,我們現(xiàn)在可以移動到實際列表視圖。
列表視圖
首先,我們打開chat_screen.dart并導(dǎo)入剛剛創(chuàng)建的文件。
`import '../model/chat_model.dart';
`
接下來,我們將小部件從Stateless更改為Stateful
從
```
class ChatScreen extends StatelessWidget {
? @override
? Widget build(BuildContext context){
? ? return new Container(
? ? ? child: new Center(
? ? ? ? child: new Text('Hello from Chat Screen ', style: new TextStyle(fontSize: 20.0),),
? ? ? )
? ? );
? }
}
```
到
```
class ChatScreen extends StatefulWidget {
? _ChatScreen createState() => new _ChatScreen();
}
class _ChatScreen extends State {
? @override
? Widget build(BuildContext context) {
? ? return new Container();
? }
}
```
是時候去玩有趣的東西,用ListView.builder替換Container。 ListView允許我們在屏幕上顯示滾動的小部件數(shù)組。 它有許多不同的屬性,但我們將要使用的是itemCount和itemBuilder。 itemCount不應(yīng)等于零。 itemBuilder用于構(gòu)建列表的項目。 它需要一種與Stateful和Stateless小部件非常相似的構(gòu)建方法。 主要區(qū)別在于添加索引變量。
Stateless/Stateful
`(BuildContext context)`
itemBuilder
`(BuildContext context, int index)
`
修改ChatScreen
```
class ChatScreen extends StatefulWidget {
? _ChatScreen createState() => new _ChatScreen();
}
class _ChatScreen extends State {
? @override
? Widget build(BuildContext context) {
? ? return new Container();
? }
}
```
To
```
class ChatScreen extends StatefulWidget {
? _ChatScreen createState() => new _ChatScreen();
}
class _ChatScreen extends State {
? @override
? Widget build(BuildContext context) {
? ? return new ListView.builder(
? ? ? itemCount:?
?? ? ? itemBuilder: (BuildContext context, int index) {}
? ? );
? }
}
```
對于我們的itemCount,我們將使用之前創(chuàng)建的數(shù)據(jù)列表的長度。 只需data.length的值
接下來,我們將處理聊天項目。 在itemBuilder中,創(chuàng)建一個新列。 該列是一個小部件,它在垂直數(shù)組中顯示其子節(jié)點。
? 正如您在WhatsApp中所注意到的那樣,每條聊天都有一條細細的灰色線條。 要鏡像此效果,我們使用Divider小部件。 這個小部件允許我們用屏幕分隔屏幕上的元素。 高度,顏色和縮進都可以改變,現(xiàn)在,我們只需要設(shè)置10.0的高度(數(shù)字必須是小數(shù)值)。
? 創(chuàng)建Divider后,我們將移至ListTile。 這是另一個預(yù)制的Flutter小部件,它易于使用但功能非常強大。 有不同的屬性,如leading, title 和 subtitle都'baked in'。 在Divider下,我們通過鍵入新的ListTile()來創(chuàng)建小部件。
?您的_ChatScreen類應(yīng)如下所示
```
?class _ChatScreen extends State {
? @override
? Widget build(BuildContext context) {
? ? return new ListView.builder(
? ? ? itemCount: data.length,
? ? ? itemBuilder: (BuildContext context, int index) {
? ? ? ? return new Column(
? ? ? ? ? children: [
? ? ? ? ? ? new Divider(
? ? ? ? ? ? ? height: 10.0,
? ? ? ? ? ? ),
? ? ? ? ? ? new ListTile(
? ? ? ? ? ? ),
? ? ? ? ? ],
? ? ? ? );
? ? ? },
? ? );
? }
}
```
首先,我們從Circle Avatar開始。 這是消息左側(cè)的圖片,以用戶的圖片為特色。 這在Flutter中創(chuàng)建非常簡單。 在列表磁貼中,我們將leading屬性設(shè)置為新的Circle頭像。 然后我們指定它的背景顏色和背景圖像。 背景顏色可以是您喜歡的任何顏色,在此示例中我使用灰色。 對于背景圖像,我們使用網(wǎng)絡(luò)圖像。 傳入我們數(shù)據(jù)列表中的頭像URL。使用以下代碼完成:
```
new ListTile(?
?leading: new CircleAvatar(
?backgroundColor: Colors.grey,?
?backgroundImage: new NetworkImage(data[index].avatarurl),?
?),
```
注意對于NetworkImage,我們指定data [index]。 傳遞的索引來自itemBuilder中創(chuàng)建的索引。 對于每次迭代,索引都會改變。
創(chuàng)建我們的頭像后,我們會將注意力轉(zhuǎn)移到用戶名和時間/日期。 由于這兩個位于同一行,我們可以使用Row小部件。 這與列非常相似,除了不是垂直對齊,小部件水平對齊。
```
title: new Row(
? ? mainAxisAlignment: MainAxisAlignment.spaceBetween,
? ? children: [
? ? ? new Text(data[index].username,
? ? ? ? ? style: new TextStyle(fontWeight: FontWeight.bold)),
? ? ? new Text(data[index].time,
? ? ? ? ? style: new TextStyle(color: Colors.grey, fontSize: 14.0))
? ? ],
? ),
```
同樣,我們使用數(shù)據(jù)列表中的信息,傳入索引。 此外,我們使用Text小部件的style屬性來相應(yīng)地設(shè)置它們的樣式。
最后,消息片段。 為此,我們將使用subtitle屬性。 創(chuàng)建一個容器窗口小部件,它將在文本窗口小部件的頂部添加5.0填充,該窗口小部件將分配給其子窗口。 “文本”窗口小部件將顯示該用戶的數(shù)據(jù)列表中的消息。 索引再次傳入。文本的樣式也會更改,以便增加字體大小和不同顏色。
您的文件現(xiàn)在應(yīng)該如下所示
```
import 'package:flutter/material.dart';
import '../model/chat_model.dart';
class ChatScreen extends StatefulWidget {
? _ChatScreen createState() => new _ChatScreen();
}
class _ChatScreen extends State {
? @override
? Widget build(BuildContext context) {
? ? return new ListView.builder(
? ? ? itemCount: data.length,
? ? ? itemBuilder: (BuildContext context, int index) {
? ? ? ? return new Column(
? ? ? ? ? children: [
? ? ? ? ? ? new Divider(
? ? ? ? ? ? ? height: 10.0,
? ? ? ? ? ? ),
? ? ? ? ? ? new ListTile(
? ? ? ? ? ? ? leading: new CircleAvatar(
? ? ? ? ? ? ? ? backgroundColor: Colors.grey,
? ? ? ? ? ? ? ? backgroundImage: new NetworkImage(data[index].avatarurl),
? ? ? ? ? ? ? ),
? ? ? ? ? ? ? title: new Row(
? ? ? ? ? ? ? ? mainAxisAlignment: MainAxisAlignment.spaceBetween,
? ? ? ? ? ? ? ? children: [
? ? ? ? ? ? ? ? ? new Text(data[index].username,
? ? ? ? ? ? ? ? ? ? ? style: new TextStyle(fontWeight: FontWeight.bold)),
? ? ? ? ? ? ? ? ? new Text(data[index].time,
? ? ? ? ? ? ? ? ? ? ? style: new TextStyle(color: Colors.grey, fontSize: 14.0))
? ? ? ? ? ? ? ? ],
? ? ? ? ? ? ? ),
? ? ? ? ? ? ? subtitle: new Container(
? ? ? ? ? ? ? ? ? padding: const EdgeInsets.only(top: 5.0),
? ? ? ? ? ? ? ? ? child: new Text(data[index].message,style: new TextStyle(color: Colors.grey, fontSize: 15.0) ), ),
? ? ? ? ? ? )
? ? ? ? ? ],
? ? ? ? );
? ? ? },
? ? );
? }
}
```
現(xiàn)在,如果你重新加載你的應(yīng)用程序,你應(yīng)該看到一個可操作的,可滾動的聊天列表。