
2025/12爆肝新作flutter3.38.2+dart3.10+get搭建跨平台深度混合短视频+直播+聊天app应用程序。



实现类似抖音app首页联动效果。上下滚动切换短视频、左右滚动切换页面模块。

基于最新跨平台技术框架flutter3.38.2构建项目模板。

直播页面模块实现了上下滑动切换直播效果,右侧滑入直播进场/左侧滑入礼物提示动效、商品列表、礼物、商品讲解、弹幕消息等功能。

import 'package:flutter/foundation.dart';
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 MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
// 是否windows平台
bool isWindows() {
if (kIsWeb) return false;
final platform = Theme.of(context).platform;
return platform == TargetPlatform.windows;
}
return GetMaterialApp(
title: 'Flutter3 DYMALL',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFFFF2C55)),
useMaterial3: true,
// 修复windows下字体不一致情况 - Web 平台特殊处理
// fontFamily: Platform.isWindows ? 'Microsoft YaHei' : null
fontFamily: isWindows() ? 'Microsoft YaHei' : null
),
home: const Layout(),
// 初始化路由
initialRoute: Common.isLogin() ? '/' : '/login',
// 路由页面
getPages: routePages,
// 初始化弹窗key
navigatorKey: MyDialog.navigatorKey,
);
}
}视频页面分为顶部状态栏+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;
}



























短视频页面底部播放进度条支持拖拽/点击,显示视频时长。

@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.38仿写抖音app短视频+直播+聊天实例的一些分享,希望对大家有所帮助!
最新版electron38-vite7-admin电脑端中后台管理系统
electron38-vite7-vue3os电脑端os管理系统
基于tauri2.8+vite7+vue3+element-plus仿QQ/微信聊天应用
tauri2.9-vite7-vue3admin客户端后台系统管理Exe模板
Electron38+Vite7+Pinia3+ElementPlus客户端聊天程序
最新原创uniapp-vue3-osadmin手机版后台管理系统
最新原创flutter3.27+bitsdojo_window客户端聊天Exe
基于uni-app+vue3实战短视频+聊天+直播app商城
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。