【10】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍
背景说明要提一点:我们所有的开发耗尽2个月的时间,目前只是整合与记录并且呈现过程,大家不要想的太简单,自己试试就知道了哈,而不是你们以为的很快很简单,这点请必须要知道。
闲话不多,开源仓库地址,可以观摩已经写好的代码:
https://gitee.com/youyacao/ff-flutter
https://www.youyacao.cn/freefirend
·完善了聊天即时通讯整体页面 ·完善了即时通讯聊天组件 ·完善了即时通讯切换组件 ·完善了即时通讯聊天朋友选择 ·完善了vip打开的vip详细页面
assets/images/msg_friend_icon.png | Bin 0 -> 6133 bytes
assets/images/msg_note_icon.png | Bin 0 -> 4657 bytes
assets/images/vip_diamond.png | Bin 0 -> 19157 bytes
assets/images/vip_gold.png | Bin 0 -> 18020 bytes
assets/images/vip_regular.png | Bin 0 -> 13222 bytes
lib/routes/app_pages.dart | 6 ++
lib/routes/app_routes.dart | 4 +
lib/screens/account/widgets/open_vip.dart | 78 ++++++++------
lib/screens/index.dart | 2 +-
lib/screens/message_screen.dart | 16 ---
lib/screens/messages/index.dart | 9 ++
.../messages/widgets/chat_section/index.dart | 37 +++++++
.../widgets/chat_section/widgets/chat_item.dart | 82 +++++++++++++++
.../widgets/chat_section/widgets/chat_list.dart | 90 ++++++++++++++++
.../widgets/chat_section/widgets/chat_tab_bar.dart | 42 ++++++++
lib/screens/messages/widgets/friend_section.dart | 81 +++++++++++++++
lib/screens/messages/widgets/message_header.dart | 56 ++++++++++
.../messages/widgets/message_screen_widget.dart | 30 ++++++
.../messages/widgets/notification_item.dart | 56 ++++++++++
lib/screens/vip/index.dart | 21 ++++
lib/screens/vip/widgets/member_combo.dart | 114 +++++++++++++++++++++
lib/screens/vip/widgets/vip_header.dart | 46 +++++++++
lib/screens/vip/widgets/vip_user_info.dart | 47 +++++++++
pubspec.lock | 46 ++++-----
24 files changed, 789 insertions(+), 74 deletions(-)
create mode 100644 assets/images/msg_friend_icon.png
create mode 100644 assets/images/msg_note_icon.png
create mode 100644 assets/images/vip_diamond.png
create mode 100644 assets/images/vip_gold.png
create mode 100644 assets/images/vip_regular.png
delete mode 100644 lib/screens/message_screen.dart
create mode 100644 lib/screens/messages/index.dart
create mode 100644 lib/screens/messages/widgets/chat_section/index.dart
create mode 100644 lib/screens/messages/widgets/chat_section/widgets/chat_item.dart
create mode 100644 lib/screens/messages/widgets/chat_section/widgets/chat_list.dart
create mode 100644 lib/screens/messages/widgets/chat_section/widgets/chat_tab_bar.dart
create mode 100644 lib/screens/messages/widgets/friend_section.dart
create mode 100644 lib/screens/messages/widgets/message_header.dart
create mode 100644 lib/screens/messages/widgets/message_screen_widget.dart
create mode 100644 lib/screens/messages/widgets/notification_item.dart
create mode 100644 lib/screens/vip/index.dart
create mode 100644 lib/screens/vip/widgets/member_combo.dart
create mode 100644 lib/screens/vip/widgets/vip_header.dart
create mode 100644 lib/screens/vip/widgets/vip_user_info.dart
这里上一篇很多人 问那些图片怎么弄的,看清楚
create mode 100644 assets/images/vip_gold.png
create mode 100644 assets/images/vip_regular.png
delete mode 100644 lib/screens/message_screen.dart
create mode 100644 lib/screens/messages/index.dart
这类型,说明没有仔细看第一篇,第一篇详细讲述了我们的资源文件要存放至 assets 资源文件夹对应目录,在第二篇的时候还做了目录框架规划,这里请注意了。
首先本项目已经确定是采用腾讯云sdk,因此我们登陆腾讯云,我们以直播sdk来区分介绍信息,我们登陆直播sdk管理处
我们可以看到现在的直播lisence是可以免费创建测试的,以前是创建测试也是收费的,这点须知,这里我们先跳过 先来讲有ui集成和无ui集成
这个地址就是有关腾讯云直播SDK的技术文档地址了: https://cloud.tencent.com/document/product/454/72057 这个就是有UI集成的方案,有UI集成是TUIkit方案,大白话就是这个方案是腾讯云官方提供的,也是比较好用的。 TUIkit 是腾讯云音视频团队结合业内主流的音视频场景,提炼出的开源解决方案,包含视频通话组件、直播组件、视频房间组件等多个客户端音视频组件,可以帮助开发者快速搭建诸如通话、客服、直播、语聊、教育等场景解决方案。
我们点击继续查看组件详细情况,那么也就是说这个带ui的集成sdk方案的界面基本也就是这个样子了。
有ui的集成方案的组件叫做TUIPusher 组件,
TUIPusher 组件是一套开源的、完整的视频直播互动推流组件,它基于腾讯云 直播 Live SDK 和 即时通信 IM SDK ,实现直播推流,直播 PK 等功能,同时支持弹幕、点赞、美颜等外挂插件,使用 TUIPusher 组件您可以快速搭建诸如秀场直播、电商直播等场景化解决方案。
优势:集成速度快,降低开发成本和周期 弊端:只能采用已经做好的这个默认的UI方案。
再看无ui集成方案,
说明实例部分
无ui集成相对复杂,难度几何增长,因此腾讯云官方为了考虑技术团队开发的成本提供了官方demo可以下载
为了帮助您更好地上手移动端直播 APP 的搭建工作,我们推出了腾讯云 MLVB-API-Example Demo,您可以根据下列操作指引快速跑通 Demo。 本文主要介绍如何快速运行腾讯云 MLVB-API-Example(Android)。
提供了原生demo,无ui集成相当于只能参考每个地方的接口,把所有的类和对象也有提供给你。
这是我们关于项目的界面,因此我们是无UI集成。
那么综上所述我们的项目是无UI集成,我们的难度更高,工作量更大,在现实商业项目中研发费用也更高,因此每个页面都是独立要先写的。
其他部分SDK以此类推,举一反三,其中本项目中要用到的SDK有,实时音视频sdk,即时通讯sdk,直播sdk,国际版短信发送SDK,介绍完毕,我们来看书写的代码。
主要增加的代码在message 部分,也就是用来做聊天的,
chat_item.dart 聊天框
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class ChatItem extends StatelessWidget {
final String name;
final String message;
final String time;
final bool hasNewMessage;
final bool isFirst;
const ChatItem({
required this.name,
required this.message,
required this.time,
this.hasNewMessage = false,
this.isFirst = false,
});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(
left: 30.w,
right: 30.w,
top: isFirst ? 20.h : 20.h,
bottom: 20.h,
),
child: Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(36.r),
child: Image.asset(
'assets/images/girl.png',
width: 72.w,
height: 72.h,
fit: BoxFit.cover,
),
),
SizedBox(width: 24.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
name,
style: TextStyle(
color: Colors.white,
fontSize: 32.sp,
fontWeight: FontWeight.bold,
),
),
Text(
time,
style: TextStyle(
color: Colors.grey,
fontSize: 26.sp,
),
),
],
),
SizedBox(height: 8.h),
Text(
message,
style: TextStyle(
color:
hasNewMessage ? const Color(0xFFFF3034) : Colors.grey,
fontSize: 28.sp,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
);
}
}
chat_list.dart 聊天列表
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'chat_item.dart';
class ChatList extends StatelessWidget {
final bool isFriend;
const ChatList({required this.isFriend});
@override
Widget build(BuildContext context) {
final List<Map<String, dynamic>> chatData = isFriend
? [
{
'name': 'ANNA',
'message': 'There is a new message',
'time': '15:23',
'hasNewMessage': true,
},
{
'name': 'ANNA',
'message': 'hello!',
'time': '15:23',
'hasNewMessage': false,
},
{
'name': 'Lily',
'message': 'hello!',
'time': '15:23',
'hasNewMessage': false,
},
{
'name': 'Lily',
'message': 'hello!',
'time': '15:23',
'hasNewMessage': true,
},
]
: [
{
'name': 'Sarah',
'message': 'Nice to meet you!',
'time': '16:30',
'hasNewMessage': true,
},
{
'name': 'Emma',
'message': 'How are you?',
'time': '16:28',
'hasNewMessage': false,
},
{
'name': 'Sophie',
'message': 'I like your photos!',
'time': '16:25',
'hasNewMessage': true,
},
{
'name': 'Olivia',
'message': 'Can we be friends?',
'time': '16:20',
'hasNewMessage': false,
},
];
return ListView.separated(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
padding: EdgeInsets.only(top: 10.h),
itemCount: chatData.length,
separatorBuilder: (context, index) => Padding(
padding: EdgeInsets.symmetric(horizontal: 30.w),
child: Divider(
height: 1.h,
color: Colors.white.withOpacity(0.1),
),
),
itemBuilder: (context, index) {
final chat = chatData[index];
return ChatItem(
name: chat['name'],
message: chat['message'],
time: chat['time'],
hasNewMessage: chat['hasNewMessage'],
isFirst: index == 0,
);
},
);
}
}
这段代码定义了一个名为 ChatList
的无状态小部件,用于显示聊天列表。根据 isFriend
参数的不同,展示不同的聊天数据。每个聊天项通过 ChatItem
小部件展示,包含名称、消息、时间和是否有新消息的标志。
flowchart TD
A[开始] --> B{判断 isFriend}
B -->|是| C[使用朋友聊天数据]
B -->|否| D[使用非朋友聊天数据]
C --> E[创建 ListView]
D --> E
E --> F[遍历聊天数据]
F --> G{是否为第一个元素}
G -->|是| H[设置 isFirst 为 true]
G -->|否| I[设置 isFirst 为 false]
H --> J[生成 ChatItem]
I --> J
J --> K[返回 ChatItem]
K --> F
chat_tab_bar 聊天页面的切换
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class ChatTabBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.centerLeft,
child: Theme(
data: ThemeData(
tabBarTheme: TabBarTheme(
labelPadding:
EdgeInsets.symmetric(horizontal: 30.w, vertical: 10.h),
tabAlignment: TabAlignment.start,
),
),
child: TabBar(
isScrollable: true,
indicatorWeight: 4.h,
indicatorSize: TabBarIndicatorSize.label,
indicatorColor: const Color(0xFFFF3034),
labelColor: Colors.white,
unselectedLabelColor: Colors.grey,
labelStyle: TextStyle(
fontSize: 32.sp,
fontWeight: FontWeight.bold,
),
unselectedLabelStyle: TextStyle(
fontSize: 32.sp,
fontWeight: FontWeight.normal,
),
dividerColor: Colors.transparent,
// labelPadding: EdgeInsets.symmetric(horizontal: 30.w),
tabs: const [
Tab(text: 'Friend'),
Tab(text: 'Stranger'),
],
),
),
);
}
}
index.dart 聊天首页
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:ff_flutter/screens/messages/widgets/chat_section/widgets/chat_tab_bar.dart';
import 'package:ff_flutter/screens/messages/widgets/chat_section/widgets/chat_list.dart';
class ChatSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(top: 30.h, left: 30.w, right: 30.w),
decoration: BoxDecoration(
color: const Color(0xFF151313),
borderRadius: BorderRadius.circular(30.r),
),
child: DefaultTabController(
length: 2,
child: SizedBox(
height: 1000.h,
child: Column(
children: [
ChatTabBar(),
Expanded(
child: TabBarView(
physics: const NeverScrollableScrollPhysics(),
children: const [
ChatList(isFriend: true),
ChatList(isFriend: false),
],
),
),
],
),
),
),
);
}
}
聊天朋友
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class FriendSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(30.w, 50.h, 30.w, 0),
child: Container(
height: 112.h,
decoration: BoxDecoration(
color: const Color(0xFF151313),
borderRadius: BorderRadius.circular(30.r),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
SizedBox(width: 32.w),
Image.asset(
'assets/images/msg_friend_icon.png',
width: 72.w,
height: 72.h,
),
SizedBox(width: 24.w),
Row(
children: [
Text(
'My friend',
style: TextStyle(
color: Colors.white,
fontSize: 28.sp,
fontWeight: FontWeight.normal,
),
),
SizedBox(width: 16.w),
Text(
'(30)',
style: TextStyle(
color: Colors.white,
fontSize: 28.sp,
),
),
],
),
],
),
Row(
children: [
Container(
padding:
EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
decoration: BoxDecoration(
color: const Color(0xFFFF3034),
borderRadius: BorderRadius.circular(24.r),
),
child: Text(
'new',
style: TextStyle(
color: Colors.white,
fontSize: 24.sp,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(width: 16.w),
Icon(
Icons.chevron_right,
color: Colors.white,
size: 48.sp,
),
SizedBox(width: 32.w),
],
),
],
),
),
);
}
}
notification_item.dart
消息通知
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class NotificationItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(30.w, 30.h, 30.w, 0),
child: Container(
height: 128.h,
decoration: BoxDecoration(
color: const Color(0xFF151313),
borderRadius: BorderRadius.circular(30.r),
),
child: Padding(
padding:
EdgeInsets.only(left: 30.w, right: 20.w, top: 20.h, bottom: 20.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset(
'assets/images/msg_note_icon.png',
width: 72.w,
height: 72.h,
),
SizedBox(width: 24.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'15:23',
style: TextStyle(
color: Colors.grey,
fontSize: 26.sp,
),
),
SizedBox(height: 8.h),
Text(
'ANNA followed you',
style: TextStyle(
color: Colors.white,
fontSize: 28.sp,
),
),
],
),
),
],
),
),
),
);
}
}
还有几个小的不看了就,在下面是vip开通
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class MemberCombo extends StatefulWidget {
@override
State<MemberCombo> createState() => _MemberComboState();
}
class _MemberComboState extends State<MemberCombo> {
int selectedIndex = 0;
final List<Map<String, dynamic>> memberTypes = [
{
'title': 'Regular member',
'icon': 'assets/images/vip_regular.png',
'darkColor': const Color(0xFF393939),
},
{
'title': 'Gold Membership',
'icon': 'assets/images/vip_gold.png',
'darkColor': const Color(0xFF393939),
},
{
'title': 'Diamond',
'icon': 'assets/images/vip_diamond.png',
'darkColor': const Color(0xFF393939),
},
];
final Gradient selectedGradient = const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFECD29F),
Color(0xFFE1BA7F),
],
);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(top: 60.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(left: 30.w, bottom: 38.h),
child: Text(
'Member Combo',
style: TextStyle(
color: Colors.white,
fontSize: 40.sp,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(
height: 186.h,
child: ListView.builder(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(horizontal: 30.w),
itemCount: memberTypes.length,
itemBuilder: (context, index) {
final isSelected = selectedIndex == index;
return GestureDetector(
onTap: () {
setState(() {
selectedIndex = index;
});
},
child: Container(
width: 296.w,
margin: EdgeInsets.only(right: 20.w),
decoration: BoxDecoration(
gradient: isSelected ? selectedGradient : null,
color:
isSelected ? null : memberTypes[index]['darkColor'],
borderRadius: BorderRadius.circular(30.r),
),
child: Stack(
children: [
Positioned(
left: 30.w,
top: 30.h,
child: Image.asset(
memberTypes[index]['icon'],
width: 48.w,
height: 48.h,
),
),
Positioned(
left: 30.w,
bottom: 30.h,
child: Text(
memberTypes[index]['title'],
style: TextStyle(
color: Colors.white,
fontSize: 32.sp,
fontWeight: FontWeight.w500,
),
),
),
],
),
),
);
},
),
),
],
),
);
}
}
核心在这个部分,
这段代码实现了一个会员组合选择界面,用户可以通过点击不同的会员类型卡片来选择会员等级。界面包含一个标题和一个水平滚动的会员卡片列表,每个卡片显示会员图标和名称。选中的卡片会高亮显示。
mermaid
flowchart TD
A[初始化] --> B[构建界面]
B --> C{是否点击卡片}
C -->|Yes| D[更新选中索引]
D --> E[重新构建界面]
C -->|No| F[保持当前状态]
我们在模拟器来看看效果:
聊天页面
开通vip的页面
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。