Flutter入门(九)微信项目---聊天列表页

今天我们就来完成微信项目中的最后一个页面聊天列表页

微信聊天列表页

在开始之前我们先准备一些数据

创建获取数据的接口

我们可以通过这个网址来构建我们的测试接口

点击新建街口,就可以自定义我们需要数据格式的接口了

现在接口有了,根据我们的页面我们还差显示的数据

获取数据

https://randomuser.me 数据地址
http://mockjs.com/ 使上面的数据随机出现

现在我们的数据已经接口都已经准备好了,我们开始构建页面吧

分析UI

我们先来分析整个UI,整个页面由3个元素所组成

  • 1.导航栏右边菜单按钮,已经菜单
  • 2.导航栏下方的搜索框
  • 3.聊天列表

微信聊天列表页

①导航栏

class ChatPage extends StatefulWidget {
  const ChatPage({Key? key}) : super(key: key);

  @override
  State<ChatPage> createState() => _ChatPageState();
}

class _ChatPageState extends State<ChatPage> {
  //下拉菜单Itme
  PopupMenuItem<String> _menuItem(String imageName, String text) {
    return PopupMenuItem(
        child: Row(
          children: [
            //图标
            Image(
              image: AssetImage(imageName),
              width: 25,
            ),
            SizedBox(width: 20),
            //文字
            Text(
              text,
              style: const TextStyle(
                color: Colors.white
              ),
            ),
          ],
        )
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: themeColor,
        elevation: 0.0,
        title: const Text(
          '微信',
          style: TextStyle(
            color: Colors.black,
          ),
        ),
        actions: [
          Container(
            margin: EdgeInsets.only(right: 10),
            child: PopupMenuButton(
              //调整展开位置
              offset: const Offset(0, 60),
              color: const Color.fromRGBO(1, 1, 1, 0.65),
              itemBuilder: (BuildContext context) {
                return <PopupMenuItem<String>>[
                  _menuItem('images/icon_chat_white.png', '发起群聊'),
                  _menuItem('images/icon_add_friends.png', '添加朋友'),
                  _menuItem('images/icon_scanning_white.png', '扫一扫'),
                  _menuItem('images/icon_payment.png', '收付款'),
                ];
              },
              child: const Image(
                width: 25,
                image: AssetImage('images/icon_add.png'),
              ),
            ),
          ),
        ],
      ),
      body: Container(),
    );
  }
}
  • PopupMenuButton 下拉菜单列表

②获取数据

网络请求这里用了http三方库
pubspec.yaml文件中

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  http: ^0.13.5

获取数据

  List<Chat> _datas = [];

  @override
  void initState() {
    super.initState();
    _getDatas()
        .then((List<Chat> datas) {
      debugPrint('数据来了!');
      if (!_cancelConnect) {
        debugPrint('更新数据!');
        setState(() {
          _datas = datas;
        });
      }
    })
        .catchError((e) {
      debugPrint(e);
    })
        .whenComplete(() => debugPrint('完毕!'))
        .timeout(const Duration(seconds: 6))
        .catchError((timeout) {
      _cancelConnect = true;
      debugPrint('超出时间:$timeout');
    });
  }

  Future<List<Chat>> _getDatas() async {
    //发送网络请求
    final url = Uri.parse('http://rap2api.taobao.org/app/mock/307918/api/chat/list');
    final response = await http.get(url);
    if (response.statusCode == 200) {
      Map responseBody = json.decode(response.body);
      List list = responseBody['chat_list'];
      List<Chat> chatList = list.map((e) => Chat.fromJson(e)).toList();
      return chatList;
    }else {
      throw Exception('statusCode:${response.statusCode}');
    }
  }

Future<List<Chat>> _getDatas() async异步不是多线程

数据获取下来并保存在_datas中了,我们开始完成列表

class ChatPage extends StatefulWidget {
  const ChatPage({Key? key}) : super(key: key);

  @override
  State<ChatPage> createState() => _ChatPageState();
}

class _ChatPageState extends State<ChatPage> {

  bool _cancelConnect = false;
  List<Chat> _datas = [];

  @override
  void initState() {
    super.initState();
    _getDatas()
        .then((List<Chat> datas) {
      debugPrint('数据来了!');
      if (!_cancelConnect) {
        debugPrint('更新数据!');
        setState(() {
          _datas = datas;
        });
      }
    })
        .catchError((e) {
      debugPrint(e);
    })
        .whenComplete(() => debugPrint('完毕!'))
        .timeout(const Duration(seconds: 6))
        .catchError((timeout) {
      _cancelConnect = true;
      debugPrint('超出时间:$timeout');
    });
  }

  Future<List<Chat>> _getDatas() async {
    //发送网络请求
    final url = Uri.parse('http://rap2api.taobao.org/app/mock/307918/api/chat/list');
    final response = await http.get(url);
    if (response.statusCode == 200) {
      Map responseBody = json.decode(response.body);
      List list = responseBody['chat_list'];
      List<Chat> chatList = list.map((e) => Chat.fromJson(e)).toList();
      return chatList;
    }else {
      throw Exception('statusCode:${response.statusCode}');
    }
  }

  PopupMenuItem<String> _menuItem(String imageName, String text) {
    return PopupMenuItem(
        child: Row(
          children: [
            //图标
            Image(
              image: AssetImage(imageName),
              width: 25,
            ),
            SizedBox(width: 20),
            //文字
            Text(
              text,
              style: const TextStyle(
                color: Colors.white
              ),
            ),
          ],
        )
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: themeColor,
        elevation: 0.0,
        title: const Text(
          '微信',
          style: TextStyle(
            color: Colors.black,
          ),
        ),
        actions: [
          Container(
            margin: EdgeInsets.only(right: 10),
            child: PopupMenuButton(
              //调整展开位置
              offset: const Offset(0, 60),
              color: const Color.fromRGBO(1, 1, 1, 0.65),
              itemBuilder: (BuildContext context) {
                return <PopupMenuItem<String>>[
                  _menuItem('images/icon_chat_white.png', '发起群聊'),
                  _menuItem('images/icon_add_friends.png', '添加朋友'),
                  _menuItem('images/icon_scanning_white.png', '扫一扫'),
                  _menuItem('images/icon_payment.png', '收付款'),
                ];
              },
              child: const Image(
                width: 25,
                image: AssetImage('images/icon_add.png'),
              ),
            ),
          ),
        ],
      ),
      body: Container(
        child: _datas.isEmpty
            ? const Center(
                child: Text('Loading...'),
              )
            : ListView.builder(
                itemCount: _datas.length,
                itemBuilder: _itemForRow
            ),
      ),
    );
  }

  Widget _itemForRow(BuildContext context, int index) {
    return ListTile(
        title: Text(_datas[index].name),
        subtitle: Container(
          padding: const EdgeInsets.only(right: 10),
          height: 20,
          child: Text(
            _datas[index].message,
            overflow: TextOverflow.ellipsis,
          ),
        ),
        leading: Container(
          width: 44,
          height: 44,
          decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(6.0),
              image: DecorationImage(
                image: NetworkImage(_datas[index].imageName),
              )
          ),
        ),
      );
  }
}

③搜索框

class SearchCell extends StatelessWidget {
  final List<Chat> datas;
  const SearchCell({Key? key, required this.datas}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        Navigator.of(context).push(
            MaterialPageRoute(builder: (BuildContext context) => SearchPage(datas: datas)));
      },
      child: Container(
        color: themeColor,
        height: 44,
        padding: const EdgeInsets.all(5),
        child: Stack(
          alignment: Alignment.center,
          children: [
            //白色底
            Container(
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(6.0),
              ),
            ),
            //图片+文字
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                //图片
                Image(
                  image: AssetImage('images/icon_magnifier_black.png'),
                  color: Colors.grey,
                  width: 15,
                ),
                //文字
                Text(
                  '搜索',
                  style: TextStyle(
                    color: Colors.grey,
                    fontSize: 15,
                  ),
                )
              ],
            ),
          ],
        ),
      ),
    );
  }
}

最后我们的页面就基本完成,我们来看下最终的效果

聊天页效果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容