动态

详情 返回 返回

flutter3-dymall仿抖音直播商城|Flutter3.27短視頻+直播+聊天App實例 - 动态 详情

自研flutter3.27+dart3.6+getx實戰抖音短視頻+聊天+直播電商帶貨app商城應用。

flutter_dymall一款基於最新版Flutter3.27+Dart3.x+Getx+mediaKit原創實戰研發抖音app帶貨商城項目。集成了直播+短視頻+聊天三大功能模塊。實現了類似抖音app首頁全屏沉浸式聯動左右滑動頁面模塊、上下滑動短視頻效果。

最新版uniapp+vue3+uv-ui跨三端短視頻+直播+聊天【H5+小程序+App端】

使用技術

  • 編輯器:vscode
  • 技術框架: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
  • toast彈窗組件:shirne_dialog^4.8.3
  • 視頻套件:media_kit: ^1.1.11
  • svg圖片:flutter_svg: ^2.0.16

附上兩篇往期基於flutter3.x實戰項目案例。

flutter3+dart3聊天室|Flutter3跨平台仿微信App語音聊天/朋友圈

flutter3-winchat桌面端聊天實例|Flutter3+Dart3+Getx仿微信Exe程序

實現了類似抖音app首頁頂部狀態欄+tab菜單欄+底部菜單欄聯動效果,左右滑動切換頁面,上下滑動切換短視頻效果。

項目框架目錄

目前flutter3_dymall直播app項目已經更新到我的原創作品集,有需要的可以去看看。

flutter3.27仿抖音app商城短視頻+直播+聊天電商

flutter3入口文件

/// 入口文件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沉浸式輪播圖+tab吸附

如上圖:輪播圖延展到頂部狀態欄,實現沉浸式效果。滾動頁面tab欄固定吸附效果。

採用 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),
);

flutter3實現底部聯動tabbar

底部菜單欄依舊採用bottomNavigationBar實現切換頁面模塊。使用getx管理全局狀態聯動背景色。

中間菜單則是使用Positioned組件實現自定義功能。

@override
Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor: Colors.grey[50],
    body: pageList[pageCurrent],
    // 底部導航欄
    bottomNavigationBar: Theme(
      data: ThemeData(
        splashColor: Colors.transparent,
        highlightColor: Colors.transparent,
        hoverColor: Colors.transparent,
      ),
      child: Obx(() {
        return Stack(
          children: [
            Container(
              decoration: BoxDecoration(
                border: Border(top: BorderSide(color: Colors.black45, width: .1)),
              ),
              child: BottomNavigationBar(
                backgroundColor: bottomNavigationBgcolor(),
                fixedColor: FStyle.primaryColor,
                unselectedItemColor: bottomNavigationItemcolor(),
                type: BottomNavigationBarType.fixed,
                elevation: 1.0,
                unselectedFontSize: 12.0,
                selectedFontSize: 12.0,
                currentIndex: pageCurrent,
                items: [
                  ...navItems
                ],
                onTap: (index) {
                  setState(() {
                    pageCurrent = index;
                  });
                },
              ),
            ),
            // 自定義導航欄中間按鈕
            Positioned(
              left: MediaQuery.of(context).size.width / 2 - 18,
              top: 0,
              bottom: 0,
              child: InkWell(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Image.asset('assets/images/logo.png', width: 36.0, isAntiAlias: true, fit: BoxFit.contain,),
                  ],
                ),
                onTap: () {
                  setState(() {
                    pageCurrent = 2;
                  });
                },
              ),
            ),
          ],
        );
      }),
    ),
  );
}

flutter3實現抖音app首頁聯動tab效果

整個視頻頁分為頂部狀態欄+導航欄Tab+內容區三部分。

實現左右滑動切換頁面,上下滑動切換短視頻聯動效果。

@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短視頻直播模塊

底部播放進度條支持拖拽、點擊,顯示播放進度tip。

@override
Widget build(BuildContext context) {
  return Container(
    color: Colors.black,
    child: Column(
      children: [
        Expanded(
          child: Stack(
            children: [
              PageView.builder(
                scrollDirection: Axis.vertical,
                controller: pageController,
                onPageChanged: (index) async {
                  // 更新播放索引
                  videoModuleController.updateVideoPlayIndex(index);
                  setState(() {
                    // 重置slider參數
                    sliderValue = 0.0;
                    sliderDraging = false;
                    position = Duration.zero;
                    duration = Duration.zero;
                  });
                  player.stop();
                  await player.open(Media(videoList[index]['src']));
                },
                itemCount: videoList.length,
                itemBuilder: (context, index) {
                  return Stack(
                    children: [
                      // 視頻區域
                      Positioned(
                        top: 0,
                        left: 0,
                        right: 0,
                        bottom: 0,
                        child: GestureDetector(
                          child: Stack(
                            children: [
                              // 短視頻插件
                              Visibility(
                                visible: videoModuleController.videoPlayIndex.value == index && position > Duration.zero,
                                child: Video(
                                  controller: videoController,
                                  fit: BoxFit.cover,
                                ),
                              ),
                              // 播放/暫停按鈕
                              StreamBuilder(
                                stream: player.stream.playing,
                                builder: (context, playing) {
                                  return Visibility(
                                    visible: playing.data == false,
                                    child: Center(
                                      child: IconButton(
                                        padding: EdgeInsets.zero,
                                        onPressed: () {
                                          player.playOrPause();
                                        },
                                        icon: Icon(
                                          playing.data == true ? Icons.pause : Icons.play_arrow_rounded,
                                          color: Colors.white60,
                                          size: 80,
                                        ),
                                        style: ButtonStyle(
                                          backgroundColor: WidgetStateProperty.all(Colors.black.withAlpha(15))
                                        ),
                                      ),
                                    ),
                                  );
                                },
                              ),
                            ],
                          ),
                          onTap: () {
                            player.playOrPause();
                          },
                        ),
                      ),
                      // 右側操作欄
                      Positioned(
                        bottom: 15.0,
                        right: 6.0,
                        child: Column(
                          spacing: 15.0,
                          children: [
                            ...
                          ],
                        ),
                      ),
                      // 底部信息區域
                      Positioned(
                        bottom: 15.0,
                        left: 10.0,
                        right: 80.0,
                        child: Column(
                          ...
                        ),
                      ),
                      // mini播放進度條
                      Positioned(
                        bottom: 0.0,
                        left: 6.0,
                        right: 6.0,
                        child: Visibility(
                          visible: videoModuleController.videoPlayIndex.value == index && position > Duration.zero,
                          child: Listener(
                            child: SliderTheme(
                              data: SliderThemeData(
                                trackHeight: sliderDraging ? 6.0 : 2.0,
                                thumbShape: RoundSliderThumbShape(enabledThumbRadius: 4.0), // 調整滑塊的大小
                                overlayShape: RoundSliderOverlayShape(overlayRadius: 0), // 去掉Slider默認上下邊距間隙
                                inactiveTrackColor: Colors.white24, // 設置非活動進度條的顏色
                                activeTrackColor: Colors.white, // 設置活動進度條的顏色
                                thumbColor: Colors.white, // 設置滑塊的顏色
                                overlayColor: Colors.transparent, // 設置滑塊覆蓋層的顏色
                              ),
                              child: Slider(
                                value: sliderValue,
                                onChanged: (value) async {
                                  // debugPrint('當前視頻播放時間$value');
                                  setState(() {
                                    sliderValue = value;
                                  });
                                  // 跳轉播放時間
                                  await player.seek(duration * value.clamp(0.0, 1.0));
                                },
                                onChangeEnd: (value) async {
                                  setState(() {
                                    sliderDraging = false;
                                  });
                                  // 繼續播放
                                  if(!player.state.playing) {
                                    await player.play();
                                  }
                                },
                              ),
                            ),
                            onPointerMove: (e) {
                              setState(() {
                                sliderDraging = true;
                              });
                            },
                          ),
                        ),
                      ),
                      // 播放位置指示器
                      Positioned(
                        bottom: 100.0,
                        left: 10.0,
                        right: 10.0,
                        child: Visibility(
                          visible: sliderDraging,
                          child: DefaultTextStyle(
                            style: TextStyle(color: Colors.white54, fontSize: 18.0, fontFamily: 'Arial'),
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              spacing: 8.0,
                              children: [
                                Text(position.label(reference: duration), style: TextStyle(color: Colors.white)),
                                Text('/', style: TextStyle(fontSize: 14.0)),
                                Text(duration.label(reference: duration)),
                              ],
                            ),
                          )
                        ),
                      ),
                    ],
                  );
                },
              ),
              /// 固定層
              // 紅包廣告
              Ads(),
            ],
          ),
        ),
      ],
    ),
  );
}

直播模塊包含了頂部信息、直播禮物左側滑入、進場動效右側滑入、彈幕消息、右側講解商品、底部操作欄等功能。

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

以上就是flutter3.27實戰開發抖音app商城的一些知識分享,整個項目涉及到的知識點還是非常多的,限於篇幅就暫時分享到這裏,希望以上分享對大家有些許幫助~

flutter3-deepseek流式AI模板|Flutter3.27+Dio+DeepSeeek聊天ai助手

Uniapp-DeepSeek跨三端AI助手|uniapp+vue3+deepseek-v3流式ai聊天模板

vue3-webseek網頁版AI問答|Vite6+DeepSeek+Arco流式ai聊天打字效果

附上幾個最新跨平台實戰項目案例。

Flutter3-MacOS桌面OS系統|flutter3.32+window_manager客户端OS模板

最新研發flutter3.27+bitsdojo_window+getx客户端仿微信聊天Exe應用

最新版Flutter3.32+Dart3.8跨平台仿微信app聊天界面|朋友圈

最新版uni-app+vue3+uv-ui跨三端仿微信app聊天應用【h5+小程序+app端】

Tauri2.0-Vue3OS桌面端os平台|tauri2+vite6+arco電腦版OS管理系統

uniapp+vue3酒店預訂|vite5+uniapp預約訂房系統模板(h5+小程序+App端)

Tauri2.0+Vite5聊天室|vue3+tauri2+element-plus仿微信|tauri聊天應用

Electron31-Vue3Admin管理系統|vite5+electron+pinia桌面端後台Exe

Vite5+Electron聊天室|electron31跨平台仿微信EXE客户端|vue3聊天程序

flutter3-winchat桌面端聊天實例|Flutter3+Dart3+Getx仿微信Exe程序

Electron32-ViteOS桌面版os系統|vue3+electron+arco客户端OS管理模板

 

user avatar qngyun1029 头像 chengxuyuanlaoliu2024 头像 wang1dao 头像 garvenc 头像
点赞 4 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.