Flutter3.41+Dart3.11+Get实战仿携程/去哪儿旅行酒店预订app应用模板

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仿微信桌面端聊天系统

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

最新版uni-app+vue3+uv-ui跨端仿携程酒店预订模板【H5+小程序+App端】