Flutter3.27_Getx_DYmall跨平台仿抖音商城|flutter3.x实战短视频+直播+聊天程序
【摘要】 自研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
使用技术
- 技术框架: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
flutter3_dymall集成了直播+短视频+聊天三大功能模块。实现了类似抖音app首页全屏沉浸式联动左右滑动页面模块、上下滑动短视频。
项目框架结构
使用vscode编辑器开发,采用最新flutter3.27跨平台框架架构项目模板。
由于涵盖了短视频、直播及聊天功能,整个项目涉及到的知识点蛮多。对于想要学习及进阶及基于这个项目基础快速成型项目有参考价值。
项目入口配置
/// 入口文件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),
);
flutter3.x实现抖音app首页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实现直播模块 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)