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,
                  ),
                )
              ],
            ),
          ],
        ),
      ),
    );
  }
}

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

聊天页效果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容