flutter3-dymall仿抖音直播商城|Flutter3.27短视频+直播+聊天App实例
自研flutter3.27+dart3.6+getx实战抖音短视频+聊天+直播电商带货app商城应用。
flutter_dymall一款基于最新版Flutter3.27+Dart3.x+Getx+mediaKit原创实战研发抖音app带货商城项目。集成了直播+短视频+聊天三大功能模块。实现了类似抖音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实战项目案例。
实现了类似抖音app首页顶部状态栏+tab菜单栏+底部菜单栏联动效果,左右滑动切换页面,上下滑动切换短视频效果。
项目框架目录
目前flutter3_dymall直播app项目已经更新到我的原创作品集,有需要的可以去看看。
https://gf.bilibili.com/item/detail/1107796011
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商城的一些知识分享,整个项目涉及到的知识点还是非常多的,限于篇幅就暂时分享到这里,希望以上分享对大家有些许帮助~
附上几个最新跨平台实战项目案例。
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聊天程序
uniapp+vue3聊天室|uni-app+vite4+uv-ui跨端仿微信app聊天语音/朋友圈
flutter3-dymall仿抖音直播商城|Flutter3.27短视频+直播+聊天App实例的更多相关文章
- Vite2+Electron仿抖音|vite2.x+electron12+vant3短视频|直播|聊天
整合vite2+electron12跨平台仿抖音电脑版实战Vite2-ElectronDouYin. 基于vite2.0+electron12+vant3+swiper6+v3popup等技术跨端仿制 ...
- 基于vue+uniapp直播项目|uni-app仿抖音/陌陌直播室
一.项目简介 uni-liveShow是一个基于vue+uni-app技术开发的集小视频/IM聊天/直播等功能于一体的微直播项目.界面仿制抖音|火山小视频/陌陌直播,支持编译到多端(H5.小程序.Ap ...
- Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例
基于vue3.0构建移动端仿抖音/快手短视频+直播实战项目Vue3-DouYin. 5G时代已来,短视频也越来越成为新一代年轻人的娱乐方式,在这个特殊之年,又将再一次成为新年俗! 基于vue3.x+v ...
- uni-app仿抖音APP短视频+直播+聊天实例|uniapp全屏滑动小视频+直播
基于uniapp+uView-ui跨端H5+小程序+APP短视频|直播项目uni-ttLive. uni-ttLive一款全新基于uni-app技术开发的仿制抖音/快手短视频直播项目.支持全屏丝滑般上 ...
- iOS多种刷新样式、音乐播放器、仿抖音视频、旅游App等源码
iOS精选源码 企业级开源项目,模仿艺龙旅行App 3D立体相册,可以旋转的立方体 横竖屏切换工具,使用陀螺仪检测手机设备方向,锁屏状... Swift版Refresh(可以自定义多种样式)架构方面有 ...
- android高仿抖音、点餐界面、天气项目、自定义view指示、爬取美女图片等源码
Android精选源码 一个爬取美女图片的app Android高仿抖音 android一个可以上拉下滑的Ui效果 android用shape方式实现样式源码 一款Android上的新浪微博第三方轻量 ...
- 10分钟快速上车短视频风口:基于uniapp框架创建自己的仿抖音短视APP
在今年也就是第48次发布的<中国互联网络发展状况统计报告>有这样一个数据,21年的上半年以来,我国我国网民规模达10.11亿,其中短视频用户达8.88亿.碎片化的生活场景下,短视频成为人们 ...
- AE神奇插件TypeMonkey—抖音点赞100W+的文字视频特效是如何做出来的?
现在最火的东西,短视频必须要拥有姓名啦,抖音这些短视频平台风头正盛,我们也常常在上面看到一些文字动画Vlog,看着并不复杂,但是有些却有上百万的点击量,今天介绍的一款神奇插件——TypeMonkey, ...
- 手淘架构组最新实践 | iOS基于静态库插桩的⼆进制重排启动优化 抖音研发实践:基于二进制文件重排的解决方案 APP启动速度提升超15% 编译期插桩
抖音研发实践:基于二进制文件重排的解决方案 APP启动速度提升超15% 原创 Leo 字节跳动技术团队 2019-08-09 https://mp.weixin.qq.com/s/Drmmx5JtjG ...
- iOS 仿抖音 视频裁剪
1.最近做短视频拍摄.其中的裁剪界面要做得和抖音的视频裁剪效果一样 需求: 裁剪有一个最大裁剪时间.最小裁剪时间.左右拖动可以实时查看对应的视频画面.拖动进度条也能查看对应的画面 .拖动底部视图也能 ...
随机推荐
- luasql报错笔记
luasql 编译安装 查看mysql配置,注意 lmysqlclient 路径 [root@hmy luasql-master]# yum install mysql-devel gcc* -y [ ...
- JavaCC 研究与应用( 8000字 心得 源程序)
一.JavaCC简介 JavaCC(Java Compiler Compiler)是一个用JAVA开发的最受欢迎的语法分析生成器.这个分析生成器工具可以读取上下文无关且有着特殊意义的语法并把它转换成可 ...
- 使用redis 的订阅服务
1.业务使用场景 我们在使用表单动态添加字段,如果新增字段,再保存数据,这个时候就会出错,出错的原因是seata 再本地缓存元数据,修改物理表的时候,这个元数据并没有发生变化,因此需要刷新元数据,因为 ...
- manim边做边学--多面体
在Manim中,对于多面体,有一系列封装好的类可以直接使用. 使用它们,可以方便快速的构建正多面体: Polyhedron:通过顶点和面的参数构建任意多面体 Tetrahedron:四面体 Octah ...
- Qt tr 无法翻译
项目中碰到部分tr无法翻译的问题,最后发现由于继承QObject的子类没有加上Q_OBJECT宏.
- PM-软件最难的不是开发程序,而是需求
最近几个月,关于人工智能的惊人文章在互联网泛滥.这也引发了很多人的担心--软件开发人员可能很快就会失业,被人工智能取代.他们想象所有的企业高管和产品研究人员将绕过大多数或所有的软件开发人员,直接要求人 ...
- HLS视频加密,让您的视频内容更安全!
** 背景介绍** HLS视频加密是一种基于HTTP Live Streaming(HLS)协议的加密技术.它的核心思想是将视频切片进行加密处理,在客户端播放时需要先获取解密密钥才能正常偶发.通过这种 ...
- 用 16G 内存存放 30亿数据(Java Map)转载
在讨论怎么去重,提出用 direct buffer 建 btree,想到应该有现成方案,于是找到一个好东西: MapDB - MapDB : http://www.mapdb.org/ 以下来自:ko ...
- 反微服务架构(A Macro Services Framework)
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 反微服务架构(A Macro Services Frame ...
- x509.MarshalSm2PrivateKey
根据搜索结果,x509.MarshalSm2PrivateKey 函数需要两个参数:一个 *sm2.PrivateKey 和一个 []byte 类型的密码.以下是使用 x509.MarshalSm2P ...