Flutter3.27_Getx_DYmall跨平台仿抖音商城|flutter3.x实战短视频+直播+聊天程序

举报
yxybox 发表于 2025/02/07 15:01:06 2025/02/07
96 0 0
【摘要】 自研flutter3.27+dart3.6+getx实战抖音短视频+聊天+直播电商带货app商城应用。集成了直播+短视频+聊天三大功能模块。实现了类似抖音app首页全屏沉浸式联动左右滑动页面模块、上下滑动短视频。

之前有分享两款flutter3.x实战微信手机app和桌面端Exe聊天实例项目。这次带来春节期间爆肝全新研发的flutter3.27仿抖音app短视频+直播商城项目。

https://bbs.huaweicloud.com/blogs/421766

https://bbs.huaweicloud.com/blogs/423160

未标题-9.png

未标题-8.png

使用技术

  • 技术框架:flutter3.27.1+Dart3.6.0
  • 路由/状态管理:get: ^4.6.6
  • 本地缓存服务:get_storage: ^2.1.1
  • 瀑布流组件:flutter_staggered_grid_view^0.7.0
  • 轮播图组件:card_swiper^3.0.1
  • 弹层组件:shirne_dialog^4.8.3
  • 视频套件:media_kit: ^1.1.11

p3.gif

p4-2.gif

flutter3_dymall集成了直播+短视频+聊天三大功能模块。实现了类似抖音app首页全屏沉浸式联动左右滑动页面模块、上下滑动短视频

p4.gif

项目框架结构

使用vscode编辑器开发,采用最新flutter3.27跨平台框架架构项目模板。

360截图20250125003729216.png

p4-1.gif

由于涵盖了短视频、直播及聊天功能,整个项目涉及到的知识点蛮多。对于想要学习及进阶及基于这个项目基础快速成型项目有参考价值。

未标题-6.png

p1.gif

项目入口配置

/// 入口文件main.dart
library;

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:media_kit/media_kit.dart';
import 'package:shirne_dialog/shirne_dialog.dart';

import 'utils/common.dart';

// 引入布局页面
import 'layouts/index.dart';

// 引入路由配置
import 'router/index.dart';

void main() async {
  // 初始化get_storage存储
  await GetStorage.init();

  // 初始化media_kit视频套件
  WidgetsFlutterBinding.ensureInitialized();
  MediaKit.ensureInitialized();

  runApp(const App());
}

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter3 DYMALL',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFFFF9900)),
        useMaterial3: true,
        fontFamily: Platform.isWindows ? 'Microsoft YaHei' : null
      ),
      home: const Layout(),
      // 初始化路由
      initialRoute: Common.isLogin() ? '/' : '/login',
      // 路由页面
      getPages: routePages,
      // 初始化弹窗key
      navigatorKey: MyDialog.navigatorKey,
    );
  }
}

flutter3实现轮播图及tabs吸附功能

采用 CustomScrollView 滚动,搭配 SliverAppBar 实现顶部轮播图功能, SliverPersistentHeader 实现tab固定吸附效果。

return Scaffold(
  backgroundColor: Colors.grey[50],
  body: ScrollConfiguration(
    behavior: CustomScrollBehavior().copyWith(scrollbars: false),
    child: CustomScrollView(
      scrollBehavior: CustomScrollBehavior().copyWith(scrollbars: false),
      controller: scrollController,
      slivers: [
        SliverAppBar(
          backgroundColor: Colors.transparent,
          foregroundColor: Colors.white,
          pinned: true,
          expandedHeight: 200.0,
          titleSpacing: 10.0,
          // 搜索框(高斯模糊背景)
          title: ClipRRect(
            borderRadius: BorderRadius.circular(30.0),
            child: BackdropFilter(
              filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
              child: Container(
                ...
              ),
            ),
          ),
          actions: [
            IconButton(icon: Icon(Icons.shopping_cart_outlined), onPressed: () {},),
          ],
          // 自定义伸缩区域(轮播图)
          flexibleSpace: Container(
            decoration: BoxDecoration(
              gradient: LinearGradient(
                begin: Alignment.topLeft,
                end: Alignment.bottomRight,
                colors: [
                  Color(0xFFFF5000), Color(0xFFfcaec4)
                ]
              )
            ),
            child: FlexibleSpaceBar(
              background: Swiper.children(
                pagination: SwiperPagination(
                  builder: DotSwiperPaginationBuilder(
                    color: Colors.white70,
                    activeColor: Colors.white,
                  )
                ),
                indicatorLayout: PageIndicatorLayout.SCALE,
                children: [
                  Image.network('https://m.360buyimg.com/babel/jfs/t20271217/224114/35/38178/150060/6760d559Fd654f946/968c156726b6e822.png',),
                  Image.network('https://m.360buyimg.com/babel/jfs/t20280117/88832/5/48468/139826/6789cbcfF4e0b2a3d/9dc54355b6f65c40.jpg',),
                  Image.network('https://m.360buyimg.com/babel/jfs/t20280108/255505/29/10540/137372/677ddbc1F6cdbbed0/bc477fadedef22a8.jpg',),
                ],
              ),
            ),
          ),
        ),

        ...

        // tabbar列表
        SliverPersistentHeader(
          pinned: true,
          delegate: CustomStickyHeader(
            child: PreferredSize(
              preferredSize: Size.fromHeight(45.0),
              child: Container(
                ...
              ),
            ),
          ),
        ),

        // 瀑布流列表
        ...
      ],
    ),
  ),
  // 返回顶部
  floatingActionButton: Backtop(controller: scrollController, offset: scrollOffset),
);

002360截图20250124095719756.png

002360截图20250124095927981.png

003360截图20250124100327260.png

003360截图20250124100423015.png

003360截图20250124100643429.png

003360截图20250124101140453.png

003360截图20250124101336963.png

003360截图20250124101415860.png

003360截图20250124101459884.png

003360截图20250124101557788.png

flutter3.x实现抖音app首页Tab切换效果

p4-1.gif


@override
Widget build(BuildContext context) {
  return Scaffold(
    key: scaffoldKey,
    extendBodyBehindAppBar: true,
    appBar: AppBar(
      forceMaterialTransparency: true,
      backgroundColor: [0, 1, 4, 5].contains(videoModuleController.videoTabIndex.value) ? null : Colors.transparent,
      foregroundColor: [0, 1, 4, 5].contains(videoModuleController.videoTabIndex.value) ? Colors.black : Colors.white,
      titleSpacing: 1.0,
      leading: Obx(() => IconButton(
        icon: Badge.count(
          backgroundColor: Colors.red,
          count: 6,
          child: Icon(Icons.sort_rounded, color: tabColor(),),
        ),
        onPressed: () {
          // 自定义打开右侧drawer
          scaffoldKey.currentState?.openDrawer();
        },
      )),
      title: Obx(() {
        return ScrollConfiguration(
          behavior: CustomScrollBehavior().copyWith(scrollbars: false),
          child: TabBar(
            ...
          ),
        );
      }),
      actions: [
        Obx(() => IconButton(icon: Icon(Icons.search_rounded, color: tabColor(),), onPressed: () {},),),
      ],
    ),
    body: ScrollConfiguration(
      behavior: CustomScrollBehavior().copyWith(scrollbars: false),
      child: PageView(
        controller: pageController,
        onPageChanged: (index) {
          videoModuleController.updateVideoTabIndex(index);
          setState(() {
            tabController.animateTo(index, duration: Duration(milliseconds: 200), curve: Curves.easeInOut);
          });
        },
        children: [
          ...tabModules
        ],
      ),
    ),
    // 侧边栏
    drawer: Drawer(
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(right: Radius.circular(15.0))),
      clipBehavior: Clip.antiAlias,
      width: 300,
      child: Container(
        ...
      ),
    ),
  );
}

tab模块各个页面相互独立,滚动页面状态保持不变。

GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();

VideoModuleController videoModuleController = Get.put(VideoModuleController());

late TabController tabController = TabController(initialIndex: videoModuleController.videoTabIndex.value, length: tabList.length, vsync: this);
late PageController pageController = PageController(initialPage: videoModuleController.videoTabIndex.value, viewportFraction: 1.0);

List<String> tabList = ['订阅', '逛逛', '直播', '团购', '短剧', '关注', '同城', '精选'];
final tabModules = [
  KeepAliveWrapper(child: SubscribeModule()),
  KeepAliveWrapper(child: BrowseModule()),
  KeepAliveWrapper(child: LiveModule()),
  KeepAliveWrapper(child: BuyingModule()),
  KeepAliveWrapper(child: DramaModule()),
  AttentionModule(),
  LocalModule(),
  RecommendModule()
];

class KeepAliveWrapper extends StatefulWidget {
  final Widget child;
  const KeepAliveWrapper({super.key, required this.child});

  @override
  State<KeepAliveWrapper> createState() => _KeepAliveWrapperState();
}

class _KeepAliveWrapperState extends State<KeepAliveWrapper> with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return widget.child;
  }

  @override
  bool get wantKeepAlive => true;
}

直播模块包含了顶部信息、直播礼物左侧滑入、进场动效右侧滑入、弹幕消息、右侧讲解商品、底部操作栏等功能。

// flutter3实现直播模块  Q:282310962

@override
Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor: Colors.black,
    extendBodyBehindAppBar: true,
    appBar: AppBar(
      forceMaterialTransparency: true,
      backgroundColor: Colors.black,
      foregroundColor: Colors.white,
      toolbarHeight: 0,
    ),
    body: Column(
      children: [
        Expanded(
          child: Stack(
            children: [
              PageView.builder(
                scrollBehavior: CustomScrollBehavior().copyWith(scrollbars: false),
                scrollDirection: Axis.vertical,
                controller: pageVerticalController,
                onPageChanged: (index) async {
                  setState(() {
                    liveIndex = index;
                  });
                  player.stop();
                  await player.open(Media(liveJson[index]['src']));
                },
                itemCount: liveJson.length,
                itemBuilder: (context, index) {
                  return Stack(
                    children: [
                      // 视频区域
                      Positioned(
                        ...
                      ),

                      /// 水平滚动模块(清屏/浮层)
                      PageView(
                        scrollDirection: Axis.horizontal,
                        controller: pageHorizontalController,
                        onPageChanged: (index) {
                          // ...
                        },
                        children: [
                          // 直播清屏
                          Container(
                            ...
                          ),
                          // 直播浮层
                          Stack(
                            children: [
                              // 顶部区域
                              Positioned(
                                top: MediaQuery.of(context).padding.top + 7,
                                left: 10.0,
                                right: 0,
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    // 直播间头像
                                    Container(
                                      ...
                                    ),
                                    // 排名统计
                                    Container(
                                      ...
                                    ),
                                    // 红包活动
                                    Container(
                                      ...
                                    ),
                                  ],
                                ),
                              ),
                              // 底部区域
                              Positioned(
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    // 商品购买动效
                                    Container(
                                      ...
                                    ),

                                    // 送礼物动效
                                    AnimationLiveGift(
                                      giftQueryList: [
                                        {'label': '小心心', 'gift': 'assets/images/gift/gift1.png', 'user': 'Jack', 'avatar': 'assets/images/avatar/img02.jpg', 'num': 12},
                                        {'label': '棒棒糖', 'gift': 'assets/images/gift/gift2.png', 'user': 'Andy', 'avatar': 'assets/images/avatar/img06.jpg', 'num': 36},
                                        {'label': '大啤酒', 'gift': 'assets/images/gift/gift3.png', 'user': '一条咸鱼', 'avatar': 'assets/images/avatar/img01.jpg', 'num': 162},
                                        ...
                                      ],
                                    ),

                                    // 加入直播间动效
                                    AnimationLiveJoin(
                                      joinQueryList: [
                                        {'avatar': 'assets/images/logo.png', 'name': 'andy'},
                                        {'avatar': 'assets/images/logo.png', 'name': 'jack'},
                                        ...
                                      ],
                                    ),
                                    
                                    // 直播弹幕+商品讲解
                                    Container(
                                      margin: EdgeInsets.only(top: 7.0),
                                      height: 200.0,
                                      child: Row(
                                        ...
                                      ),
                                    ),

                                    // 底部工具栏
                                    Container(
                                      margin: const EdgeInsets.only(top: 7.0),
                                      child: Row(
                                        ...
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                            ],
                          ),
                        ],
                      ),
                    ],
                  );
                },
              ),
            ],
          ),
        ),
      ],
    ),
  );
}

作者:xiaoyan2017
链接:https://www.cnblogs.com/xiaoyan2017/p/18700875
来源:博客园
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。