【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex

简介: 【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex

【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex

章节内容【11】

【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍

开发背景

背景说明要提一点:我们所有的开发耗尽2个月的时间,目前只是整合与记录并且呈现过程,大家不要想的太简单,自己试试就知道了哈,而不是你们以为的很快很简单,这点请必须要知道。

闲话不多,开源仓库地址,可以观摩已经写好的代码:

https://gitee.com/youyacao/ff-flutter

demo下载

https://www.youyacao.cn/freefirend

更新代码文件和日志文件-gitee可见

·完善了vip购买页面的其他功能
·增加了用户邀请码页面
·增加了申请主播资料填写页面
·增加了安全中心介绍页
·增加了帮助中心介绍页
·创建腾讯云直播SDK相关信息
·创建即时通讯sdk相关信息

assets/images/invite_box.png                       | Bin 0 -> 340684 bytes
 assets/images/invite_friend_icon.png               | Bin 0 -> 13944 bytes
 assets/images/invite_gold_coin.png                 | Bin 0 -> 17238 bytes
 assets/images/vip_advance.png                      | Bin 0 -> 10671 bytes
 assets/images/vip_all_videos.png                   | Bin 0 -> 17366 bytes
 assets/images/vip_auto_renew.png                   | Bin 0 -> 6721 bytes
 assets/images/vip_hd.png                           | Bin 0 -> 15988 bytes
 assets/images/vip_no_ads.png                       | Bin 0 -> 16945 bytes
 lib/routes/app_pages.dart                          |  30 ++++
 lib/routes/app_routes.dart                         |   5 +
 lib/screens/account/widgets/menu_list.dart         |  87 ++++++----
 lib/screens/account/widgets/user_info.dart         |  27 +--
 lib/screens/anchor_apply/index.dart                |  90 ++++++++++
 .../anchor_apply/widgets/anchor_apply_form.dart    | 155 +++++++++++++++++
 lib/screens/help_center/index.dart                 |  75 ++++++++
 .../help_center/widgets/help_menu_item.dart        |  45 +++++
 lib/screens/invite_friends/index.dart              |  22 +++
 .../invite_friends/widgets/invite_card.dart        | 188 +++++++++++++++++++++
 .../invite_friends/widgets/invite_header.dart      |  41 +++++
 lib/screens/personal_data/index.dart               |  33 ++++
 .../personal_data/widgets/personal_data_form.dart  | 147 ++++++++++++++++
 lib/screens/security_center/index.dart             |  79 +++++++++
 .../widgets/security_menu_item.dart                |  45 +++++
 lib/screens/vip/index.dart                         |  27 ++-
 lib/screens/vip/widgets/member_benefits.dart       |  78 +++++++++
 lib/screens/vip/widgets/member_combo.dart          |   4 +-
 lib/screens/vip/widgets/vip_purchase.dart          |  90 ++++++++++
 27 files changed, 1218 insertions(+), 50 deletions(-)
 create mode 100644 assets/images/invite_box.png
 create mode 100644 assets/images/invite_friend_icon.png
 create mode 100644 assets/images/invite_gold_coin.png
 create mode 100644 assets/images/vip_advance.png
 create mode 100644 assets/images/vip_all_videos.png
 create mode 100644 assets/images/vip_auto_renew.png
 create mode 100644 assets/images/vip_hd.png
 create mode 100644 assets/images/vip_no_ads.png
 create mode 100644 lib/screens/anchor_apply/index.dart
 create mode 100644 lib/screens/anchor_apply/widgets/anchor_apply_form.dart
 create mode 100644 lib/screens/help_center/index.dart
 create mode 100644 lib/screens/help_center/widgets/help_menu_item.dart
 create mode 100644 lib/screens/invite_friends/index.dart
 create mode 100644 lib/screens/invite_friends/widgets/invite_card.dart
 create mode 100644 lib/screens/invite_friends/widgets/invite_header.dart
 create mode 100644 lib/screens/personal_data/index.dart
 create mode 100644 lib/screens/personal_data/widgets/personal_data_form.dart
 create mode 100644 lib/screens/security_center/index.dart
 create mode 100644 lib/screens/security_center/widgets/security_menu_item.dart
 create mode 100644 lib/screens/vip/widgets/member_benefits.dart
 create mode 100644 lib/screens/vip/widgets/vip_purchase.dart

实战开始

页面结果

先看看结果

个人中心的

邀请页面


直播页面


帮助中心页面以及安全中心页面 ,类似就一个代替

购买vip页面完善。

代码部分

先看个人中心页面的变化:

personal_data_form.dart

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class PersonalDataForm extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Padding(
        padding: EdgeInsets.symmetric(horizontal: 60.w),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            SizedBox(height: 60.h),
            _buildLabel('Profile picture'),
            SizedBox(height: 20.h),
            // 头像选择区域
            Container(
              width: 140.w,
              height: 140.h,
              decoration: BoxDecoration(
                color: const Color(0xFF393939),
                borderRadius: BorderRadius.circular(20.r),
              ),
              child: Center(
                child: Icon(
                  Icons.add,
                  color: Colors.white,
                  size: 48.sp,
                ),
              ),
            ),
            SizedBox(height: 40.h),
            _buildLabel('Name'),
            SizedBox(height: 20.h),
            _buildTextField('Name'),
            SizedBox(height: 40.h),
            _buildLabel('Date of birth'),
            SizedBox(height: 20.h),
            _buildTextField('Date of birth', suffixIcon: Icons.calendar_today),
            SizedBox(height: 40.h),
            _buildLabel('Gender'),
            SizedBox(height: 20.h),
            _buildDropdown('Choose your gender'),
            SizedBox(height: 40.h),
            _buildLabel('Area'),
            SizedBox(height: 20.h),
            _buildDropdown('Choose your region'),
            SizedBox(height: 60.h),
            _buildConfirmButton(),
          ],
        ),
      ),
    );
  }
  Widget _buildLabel(String text) {
    return Text(
      text,
      style: TextStyle(
        color: Colors.white,
        fontSize: 32.sp,
        fontWeight: FontWeight.w500,
      ),
    );
  }
  Widget _buildTextField(String hint, {IconData? suffixIcon}) {
    return Container(
      height: 100.h,
      decoration: BoxDecoration(
        color: const Color(0xFF393939),
        borderRadius: BorderRadius.circular(20.r),
      ),
      child: TextField(
        style: TextStyle(
          color: Colors.white,
          fontSize: 32.sp,
        ),
        decoration: InputDecoration(
          hintText: hint,
          hintStyle: TextStyle(
            color: Colors.grey,
            fontSize: 32.sp,
          ),
          border: InputBorder.none,
          contentPadding: EdgeInsets.symmetric(horizontal: 30.w),
          suffixIcon: suffixIcon != null
              ? Icon(
                  suffixIcon,
                  color: Colors.grey,
                  size: 48.sp,
                )
              : null,
        ),
      ),
    );
  }
  Widget _buildDropdown(String hint) {
    return Container(
      height: 100.h,
      padding: EdgeInsets.symmetric(horizontal: 30.w),
      decoration: BoxDecoration(
        color: const Color(0xFF393939),
        borderRadius: BorderRadius.circular(20.r),
      ),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(
            hint,
            style: TextStyle(
              color: Colors.grey,
              fontSize: 32.sp,
            ),
          ),
          Icon(
            Icons.keyboard_arrow_down,
            color: Colors.grey,
            size: 48.sp,
          ),
        ],
      ),
    );
  }
  Widget _buildConfirmButton() {
    return Container(
      width: double.infinity,
      height: 100.h,
      decoration: BoxDecoration(
        color: const Color(0xFFE56389),
        borderRadius: BorderRadius.circular(50.r),
      ),
      child: Center(
        child: Text(
          'Confirm Save',
          style: TextStyle(
            color: Colors.white,
            fontSize: 36.sp,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
    );
  }
}

这段代码定义了一个名为 PersonalDataForm 的无状态小部件,用于显示个人资料表单。表单包含头像选择、姓名、出生日期、性别、地区输入框及确认按钮。各个输入项通过 _buildLabel、_buildTextField、_buildDropdown 和 _buildConfirmButton 方法构建。

控制流图

flowchart TD
    A[开始] --> B[创建 SingleChildScrollView]
    B --> C[创建 Padding]
    C --> D[创建 Column]
    D --> E{添加子组件}
    E -->|Profile picture 标签| F[创建 _buildLabel]
    F --> G[创建 SizedBox]
    G --> H[创建 Container 头像选择区域]
    H --> I[创建 SizedBox]
    I --> J[创建 Name 标签]
    J --> K[创建 SizedBox]
    K --> L[创建 Name 输入框]
    L --> M[创建 SizedBox]
    M --> N[创建 Date of birth 标签]
    N --> O[创建 SizedBox]
    O --> P[创建 Date of birth 输入框]
    P --> Q[创建 SizedBox]
    Q --> R[创建 Gender 标签]
    R --> S[创建 SizedBox]
    S --> T[创建 Gender 下拉框]
    T --> U[创建 SizedBox]
    U --> V[创建 Area 标签]
    V --> W[创建 SizedBox]
    W --> X[创建 Area 下拉框]
    X --> Y[创建 SizedBox]
    Y --> Z[创建 Confirm Save 按钮]

购买vip页面的代码:

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'widgets/vip_header.dart';
import 'widgets/vip_user_info.dart';
import 'widgets/member_combo.dart';
import 'widgets/member_benefits.dart';
import 'widgets/vip_purchase.dart';
class VipScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: SafeArea(
        bottom: false, // 不处理底部安全区域
        child: Column(
          children: [
            Expanded(
              child: SingleChildScrollView(
                child: Column(
                  children: [
                    VipHeader(),
                    VipUserInfo(),
                    MemberCombo(),
                    MemberBenefits(),
                  ],
                ),
              ),
            ),
            VipPurchase(),
          ],
        ),
      ),
    );
  }
}

可以看到 首页只是用来引用组件,

vip_purchase.dart

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class VipPurchase extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 30.w),
      decoration: BoxDecoration(
        color: const Color(0xFF393939),
        borderRadius: BorderRadius.circular(4.r),
      ),
      child: Column(
        // mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          SizedBox(height: 30.h),
          Row(
            children: [
              Image.asset(
                'assets/images/vip_auto_renew.png',
                width: 32.w,
                height: 32.h,
                color: const Color(0xFFECD29F),
              ),
              SizedBox(width: 20.w),
              Text(
                'Automatic renewal',
                style: TextStyle(
                  color: const Color(0xFFECD29F),
                  fontSize: 32.sp,
                ),
              ),
            ],
          ),
          SizedBox(
            height: 133.h,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Row(
                  children: [
                    Text(
                      'Amount: ',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 32.sp,
                      ),
                    ),
                    Text(
                      '\$89',
                      style: TextStyle(
                        color: const Color(0xFFECD29F),
                        fontSize: 32.sp,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ],
                ),
                GestureDetector(
                  onTap: () {
                    print('Buy clicked');
                  },
                  child: Container(
                    width: 340.w,
                    height: 70.h,
                    decoration: BoxDecoration(
                      color: const Color(0xFFE56389),
                      borderRadius: BorderRadius.circular(35.r),
                    ),
                    child: Center(
                      child: Text(
                        'Buy',
                        style: TextStyle(
                          color: Colors.white,
                          fontSize: 36.sp,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

member_combo.dart

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: 28.sp,
                              fontWeight: FontWeight.w400,
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

本章其他界面也没有复杂的部分,其他代码直接登录gitee 去看即可,已经公开的,我们接下来直接进入SDK应用创建部分

直播sdk创建

先是直播sdk,正常用户只有一次机会,14天测试期,要珍惜,如果测试完了过期的不能删除,也无法使用

核心资料是app name License URL和License Key

即时通讯im

即时通讯的关键信息,
SDKAppID:

1600071385

应用名称:

freefirend

密钥:
这里就脱敏一下。

目录
相关文章
|
1月前
|
供应链 监控 安全
对话|企业如何构建更完善的容器供应链安全防护体系
阿里云与企业共筑容器供应链安全
171369 16
|
2天前
|
人工智能 搜索推荐 Docker
手把手教你使用 Ollama 和 LobeChat 快速本地部署 DeepSeek R1 模型,创建个性化 AI 助手
DeepSeek R1 + LobeChat + Ollama:快速本地部署模型,创建个性化 AI 助手
1594 95
手把手教你使用 Ollama 和 LobeChat 快速本地部署 DeepSeek R1 模型,创建个性化 AI 助手
|
1月前
|
供应链 监控 安全
对话|企业如何构建更完善的容器供应链安全防护体系
随着云计算和DevOps的兴起,容器技术和自动化在软件开发中扮演着愈发重要的角色,但也带来了新的安全挑战。阿里云针对这些挑战,组织了一场关于云上安全的深度访谈,邀请了内部专家穆寰、匡大虎和黄竹刚,深入探讨了容器安全与软件供应链安全的关系,分析了当前的安全隐患及应对策略,并介绍了阿里云提供的安全解决方案,包括容器镜像服务ACR、容器服务ACK、网格服务ASM等,旨在帮助企业构建涵盖整个软件开发生命周期的安全防护体系。通过加强基础设施安全性、技术创新以及倡导协同安全理念,阿里云致力于与客户共同建设更加安全可靠的软件供应链环境。
150306 32
|
9天前
|
Linux iOS开发 MacOS
deepseek部署的详细步骤和方法,基于Ollama获取顶级推理能力!
DeepSeek基于Ollama部署教程,助你免费获取顶级推理能力。首先访问ollama.com下载并安装适用于macOS、Linux或Windows的Ollama版本。运行Ollama后,在官网搜索“deepseek”,选择适合你电脑配置的模型大小(如1.5b、7b等)。通过终端命令(如ollama run deepseek-r1:1.5b)启动模型,等待下载完成即可开始使用。退出模型时输入/bye。详细步骤如下图所示,轻松打造你的最强大脑。
7578 85
|
2天前
|
机器学习/深度学习 人工智能 自然语言处理
PAI Model Gallery 支持云上一键部署 DeepSeek-V3、DeepSeek-R1 系列模型
DeepSeek 系列模型以其卓越性能在全球范围内备受瞩目,多次评测中表现优异,性能接近甚至超越国际顶尖闭源模型(如OpenAI的GPT-4、Claude-3.5-Sonnet等)。企业用户和开发者可使用 PAI 平台一键部署 DeepSeek 系列模型,实现 DeepSeek 系列模型与现有业务的高效融合。
|
10天前
|
人工智能 自然语言处理 Java
Spring AI,搭建个人AI助手
本期主要是实操性内容,聊聊AI大模型,并使用Spring AI搭建属于自己的AI助手、知识库。本期所需的演示源码笔者托管在Gitee上(https://gitee.com/catoncloud/spring-ai-demo),读者朋友可自行查阅。
925 41
Spring AI,搭建个人AI助手
|
2月前
|
弹性计算 人工智能 安全
对话 | ECS如何构筑企业上云的第一道安全防线
随着中小企业加速上云,数据泄露、网络攻击等安全威胁日益严重。阿里云推出深度访谈栏目,汇聚产品技术专家,探讨云上安全问题及应对策略。首期节目聚焦ECS安全性,提出三道防线:数据安全、网络安全和身份认证与权限管理,确保用户在云端的数据主权和业务稳定。此外,阿里云还推出了“ECS 99套餐”,以高性价比提供全面的安全保障,帮助中小企业安全上云。
201990 15
对话 | ECS如何构筑企业上云的第一道安全防线
|
2天前
|
机器学习/深度学习 人工智能 并行计算
一文了解火爆的DeepSeek R1 | AIGC
DeepSeek R1是由DeepSeek公司推出的一款基于强化学习的开源推理模型,无需依赖监督微调或人工标注数据。它在数学、代码和自然语言推理任务上表现出色,具备低成本、高效率和多语言支持等优势,广泛应用于教育辅导、金融分析等领域。DeepSeek R1通过长链推理、多语言支持和高效部署等功能,显著提升了复杂任务的推理准确性,并且其创新的群体相对策略优化(GRPO)算法进一步提高了训练效率和稳定性。此外,DeepSeek R1的成本低至OpenAI同类产品的3%左右,为用户提供了更高的性价比。
707 10
|
12天前
|
人工智能 JavaScript 前端开发
白嫖 DeepSeek ,低代码竟然会一键作诗?
宜搭低代码平台接入 DeepSeek AI 大模型能力竟然这么方便!本教程将揭秘宜搭如何快速接入 DeepSeek API,3 步打造专属作诗机器人,也许你还能开发出更多有意思的智能玩法,让创意在代码间自由生长。
1551 13
|
10天前
|
Linux iOS开发 MacOS
DeepSeek爆火,如何免费部署到你的电脑上?获取顶级推理能力教程来了
如何在本地电脑上免费部署DeepSeek,获取顶级推理能力?只需三步:1. 访问Ollama官网下载并安装对应操作系统的版本(支持macOS、Linux和Windows)。2. 打开Ollama并确保其正常运行。3. 在Ollama官网搜索并选择DeepSeek模型(如deepseek-r1),根据电脑配置选择合适的模型大小(1.5B至671B)。通过终端命令(如ollama run deepseek-r1:1.5b)运行模型,即可开始使用DeepSeek进行推理。退出模型时,在终端输入/bye。更多详情请参考Ollama官方文档。