2026爆肝研发flutter3.41.5+getx跨平台仿携程/飞猪app旅游酒店预约系统。
flutter3-hotel :基于flutter3.41+dart3.11+get+cached_network_image搭建跨平台旅行app酒店预订助手。集成了酒店首页、酒店预订/搜索/列表/详情、探索、订单、聊天消息、我的等功能模块。
使用技术
- 编辑器:vscode
- 技术框架:flutter3.41.5+dart3.11.3
- 路由/状态管理:get^4.7.3
- 本地缓存:get_storage^2.1.1
- 图片轮播组件:card_swiper^3.0.1
- 图片缓存:cached_network_image^3.4.1
- 日期选择插件:syncfusion_flutter_datepicker^33.1.49
- 弹层提示:shirne_dialog^4.9.0
- 瀑布流组件:flutter_staggered_grid_view^0.7.0
- 滚动定位组件:scrollable_positioned_list^0.3.8
项目结构目录
使用最新跨平台框架Flutter3.41初始创建项目模板。
项目入口配置
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:intl/date_symbol_data_local.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();
// 初始化国际化语言
initializeDateFormatting('zh_CN');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
/**
* 修复flutter3.32以上会出现底部导航栏背景黑色
* The bottom navigation bar is always black from flutter: 3.32.1.
* It's working fine on flutter: 3.29.3
*/
systemNavigationBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.dark,
),
child: GetMaterialApp(
title: 'Flutter3 Trip',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Color(0xffffaa00)),
useMaterial3: true,
// 修复windows下字体不一致情况
fontFamily: Platform.isWindows ? 'Microsoft YaHei' : null
),
home: const Layout(),
// 初始化路由
initialRoute: Common.isLogin() ? '/' : '/login',
// 路由页面
getPages: routePages,
// 初始化弹窗key
navigatorKey: MyDialog.navigatorKey,
),
);
}
}
注意:如果开发中遇到升级flutter3.32版本以上,出现手机底部导航栏背景黑色,可以试试如下修复方法。
AnnotatedRegion(
value: SystemUiOverlayStyle(
systemNavigationBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.dark,
),
child: MaterialApp(
...
),
)
通用布局模板
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
// 引入pages页面
import '../pages/index/index.dart';
import '../pages/hotel/index.dart';
import '../pages/message/index.dart';
import '../pages/explore/index.dart';
import '../pages/my/index.dart';
class Layout extends StatefulWidget {
const Layout({super.key});
@override
State<Layout> createState() => _LayoutState();
}
class _LayoutState extends State<Layout> with AutomaticKeepAliveClientMixin {
// page索引
int pageCurrent = 0;
// page页面
late final List<Widget> pageList = const [
IndexPage(),
HotelPage(),
ExplorePage(),
Message(),
MyPage()
];
@override
bool get wantKeepAlive => true;
// 动态生成导航项
List<BottomNavigationBarItem> buildNavItems() {
return [
BottomNavigationBarItem(
...
),
BottomNavigationBarItem(
...
),
BottomNavigationBarItem(
...
),
BottomNavigationBarItem(
...
),
BottomNavigationBarItem(
...
),
];
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
backgroundColor: Colors.grey[50],
body: IndexedStack(
index: pageCurrent,
children: pageList,
),
// 底部导航栏
bottomNavigationBar: Theme(
// Flutter去掉BottomNavigationBar底部导航栏的水波纹
data: ThemeData(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
hoverColor: Colors.transparent,
),
child: Stack(
children: [
Container(
decoration: BoxDecoration(
border: Border(top: BorderSide(color: Colors.black45, width: .1)),
),
child: BottomNavigationBar(
backgroundColor: Colors.white,
fixedColor: Color(0xffffaa00),
unselectedItemColor: Colors.black,
type: BottomNavigationBarType.fixed,
elevation: 1.0,
unselectedFontSize: 12.0,
selectedFontSize: 12.0,
currentIndex: pageCurrent,
items: buildNavItems(),
onTap: (index) {
if(pageCurrent == index) return;
setState(() {
pageCurrent = index;
});
},
),
),
// 自定义底部导航栏中间按钮
Positioned(
left: MediaQuery.of(context).size.width / 2 - 18,
top: 0,
bottom: 0,
child: InkWell(
...
),
),
],
),
),
);
}
}
flutter3自定义滚动槽
late ScrollController indicatorController = ScrollController();
// 记录滚动位置
final ValueNotifier<double> indicatorOffset = ValueNotifier(0);
@override
void initState() {
super.initState();
indicatorController.addListener(() {
indicatorOffset.value = indicatorController.position.pixels / indicatorController.position.maxScrollExtent;
});
}
Column(
children: [
Expanded(
child: SingleChildScrollView(
controller: indicatorController,
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(horizontal: 12.0),
child: Row(
...
),
),
),
// 指示槽
ValueListenableBuilder(
valueListenable: indicatorOffset,
builder: (context, offset, child) {
final indicatorWidth = 20.0;
final trackWidth = 50.0;
// 可移动的最大距离
final maxTranslate = trackWidth - indicatorWidth;
// 根据滚动进度计算位移
final translateX = maxTranslate * offset.clamp(0.0, 1.0);
return Stack(
children: [
// 轨道
Container(
decoration: BoxDecoration(
color: Color(0xffffaa00).withAlpha(50),
borderRadius: BorderRadius.circular(50.0),
),
height: 4.0,
width: trackWidth,
),
// 滑块
Transform.translate(
offset: Offset(translateX, 0),
child: Container(
decoration: BoxDecoration(
color: Color(0xffffaa00),
borderRadius: BorderRadius.circular(50.0),
),
height: 4.0,
width: indicatorWidth,
),
),
],
);
},
),
],
),
flutter3酒店预订模块
预订模块单独封装成了一个组件。
- 热门城市、位置品牌选择
使用 scrollable_positioned_list 组件实现滑动字母索引滚动到指定列表位置。
ItemScrollController itemScrollController = ItemScrollController();
ScrollablePositionedList.builder(
itemScrollController: itemScrollController,
itemCount: citylist.length,
itemBuilder: (context, index) {
// ...
}
)
// 侧边索引
Align(
alignment: Alignment.centerRight,
child: GestureDetector(
child: Container(
color: Colors.transparent,
width: 25.0,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(pinyinList.length, (index) {
return GestureDetector(
child: Container(
...
),
onTapDown: (details) {
// 跳转指定索引位置
itemScrollController.jumpTo(index: index);
setState(() {
selectedLetter = pinyinList[index];
showBubble = true;
});
Future.delayed(Duration(milliseconds: 200), () {
setState(() {
selectedLetter = '';
showBubble = false;
});
});
},
);
}),
),
),
onVerticalDragUpdate: (details) {
updateSelectedLetter(details.localPosition);
},
onVerticalDragEnd: (details) {
setState(() {
selectedLetter = '';
showBubble = false;
});
},
),
),
- 入住/离店日期选择
使用 syncfusion_flutter_datepicker 插件选择入住/离店日期。
// 入住日期
DateTime startDate = DateTime.now();
// 离店日期
DateTime endDate = DateTime.now().add(Duration(days: 1));
GestureDetector(
child: Container(
padding: EdgeInsets.all(10.0),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Color(0xfff5f5f5))),
),
child: Row(
spacing: 10.0,
children: [
Icon(Icons.calendar_month_outlined),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 3.0,
children: [
Text('入住', style: TextStyle(color: Colors.grey, fontSize: 12.0)),
Text('${DateFormat('MM-dd').format(startDate)} ${DateFormat('E', 'zh_CN').format(startDate)}'),
],
),
Container(
color: Colors.grey[50],
padding: EdgeInsets.symmetric(horizontal: 5.0, vertical: 1.0),
// DateTime 类提供了 difference 方法,可以计算两个日期之间的时间差,返回一个 Duration 对象。通过 Duration 的 inDays 属性,可以获取天数差。
child: Text('共${endDate.difference(startDate).inDays}晚'),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
spacing: 3.0,
children: [
Text('离店', style: TextStyle(color: Colors.grey, fontSize: 12.0)),
Text('${DateFormat('MM-dd').format(endDate)} ${DateFormat('E', 'zh_CN').format(endDate)}'),
],
),
],
),
),
Icon(Icons.arrow_forward_ios_rounded, color: Colors.grey, size: 12.0,)
],
),
),
onTap: () {
handleCalendar();
},
)
void handleCalendar() {
showModalBottomSheet(
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(0.0))),
context: context,
builder: (BuildContext context) {
return Column(
children: [
Expanded(
child: SfDateRangePicker(
selectionMode: DateRangePickerSelectionMode.range,
selectionShape: DateRangePickerSelectionShape.rectangle,
// 初始日期范围
initialSelectedRange: PickerDateRange(startDate, endDate),
minDate: DateTime.now(),
maxDate: DateTime.now().add(Duration(days: 450)),
backgroundColor: Colors.white,
// 日期区间颜色
startRangeSelectionColor: Color(0xFF006ff6),
endRangeSelectionColor: Color(0xFF006ff6),
rangeSelectionColor: Color(0xFFe3f0f9),
// 选中颜色
selectionColor: Color(0xFF006ff6),
rangeTextStyle: TextStyle(color: Color(0xFF006ff6)),
monthViewSettings: DateRangePickerMonthViewSettings(
// 改变一周的第一天
firstDayOfWeek: 1,
viewHeaderStyle: DateRangePickerViewHeaderStyle(
textStyle: TextStyle(color: Color(0xFF130438), fontSize: 12, fontFamily: 'Arial'),
),
dayFormat: 'EE',
),
// 自定义头部样式
headerStyle: DateRangePickerHeaderStyle(
backgroundColor: Colors.white,
textAlign: TextAlign.center
),
// 日期单元格样式
monthCellStyle: DateRangePickerMonthCellStyle(
cellDecoration: BoxDecoration(
// color: Color(0xFFf7f4ff),
),
todayTextStyle: TextStyle(color: Color(0xFF006ff6)),
disabledDatesTextStyle: TextStyle(color: Colors.black26),
weekendTextStyle: TextStyle(color: Colors.red.withAlpha(200)),
),
// showTodayButton: true,
// showActionButtons: true,
onSelectionChanged: (DateRangePickerSelectionChangedArgs args) {
setState(() {
if(args.value.startDate != null && args.value.endDate != null) {
startDate = args.value.startDate;
endDate = args.value.endDate;
Future.delayed(Duration(seconds: 1), () {
Get.back();
});
}
});
},
),
),
],
);
},
);
}
flutter3聊天消息模块
项目中新增了客服聊天消息功能模块。
最新版Flutter3.32+Dart3.8跨平台仿微信app聊天界面|朋友圈
最新版Flutter3.38+Dart3.10仿写抖音APP直播+短视频+聊天应用程序
最新研发flutter3.27+bitsdojo_window+getx客户端仿微信聊天Exe应用
Flutter3-MacOS桌面OS系统|flutter3.32+window_manager客户端OS模板
flutter3自定义酒店筛选列表
使用 SizeTransition 和 FadeTransition 组件实现下拉动画效果。
// 筛选下拉框
if(dropdownVisible)
Positioned(
top: dropdownOffset,
height: MediaQuery.of(context).size.height - dropdownOffset,
width: MediaQuery.of(context).size.width,
child: ScrollConfiguration(
behavior: CustomScrollBehavior(),
child: Material(
color: Colors.transparent,
child: Column(
children: [
SizeTransition(
sizeFactor: animation, // 高度展开动画
axis: Axis.vertical, // 垂直方向展开
child: Container(
color: Colors.white,
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if(dropdownIndex == 0)
dropOption1(),
if(dropdownIndex == 1)
dropOption2(),
if(dropdownIndex == 2)
dropOption3(),
if(dropdownIndex == 3)
dropOption4(),
],
),
),
),
Expanded(
child: FadeTransition(
opacity: animation,
child: GestureDetector(
child: Container(
color: Colors.black54,
),
onTap: () {
setState(() {
closeDropdown();
});
},
),
),
),
],
),
),
),
)
以上就是flutter3.41搭建旅行酒店预订app项目的一些知识分享,希望对大家有点帮助!
附上一些最新原创项目实例
flutter3.41+deepseek+dio+getx纯手搓桌面客户端ai流式智能对话系统
Flutter3.41+DeepSeek智能AI应用|flutter3+getx+dio流式ai对话app模板
uniapp+deepseek流式ai助理|uniapp+vue3对接deepseek三端Ai问答模板
Vite8+DeepSeek网页版AI助手|vue3+arco本地web版ai流式打字问答系统
Electron41+Vite8.0+DeepSeek桌面端AI助手|electron+vue3流式ai系统
最新版Flutter3.38+Dart3.10仿写抖音APP直播+短视频+聊天应用程序
Tauri2.9+Vue3桌面版OS系统|vite7+tauri2+arcoDesign电脑端os后台模板
electron38-admin桌面端后台|Electron38+Vue3+ElementPlus管理系统
Electron38-Wechat电脑端聊天|vite7+electron38仿微信桌面端聊天系统