【maaath】 Flutter for OpenHarmony 打车出行应用跨平台实践
本文详细介绍了如何使用 Flutter 在 OpenHarmony 平台上构建一个功能完整的打车出行应用。通过分层架构设计、数据模型抽象、服务层封装和 Material Design UI 构建,我们实现了附近车辆搜索、价格预估比较、预约叫车、行程记录管理、司机评价、紧急求助等核心功能。Flutter 优秀的跨平台能力和 OpenHarmony 生态的快速发展,为开发者提供了广阔的应用开发空间。希
Flutter 打车出行应用在 OpenHarmony 上的跨平台实践
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
作者:maaath
一、引言
随着 OpenHarmony 生态的快速发展,跨平台开发框架在鸿蒙设备上的适配成为开发者关注的焦点。Flutter 作为业界领先的跨平台 UI 框架,凭借其高性能渲染引擎和丰富的组件生态,已经成为 OpenHarmony 应用开发的重要选择之一。
本文将基于笔者在实际项目中开发的打车出行应用,详细介绍如何使用 Flutter 在 OpenHarmony 设备上构建一个功能完整的打车应用。该应用涵盖了附近车辆搜索、价格预估比较、预约叫车、行程记录管理、司机评价、紧急求助等核心功能,完整展示了 Flutter 在 OpenHarmony 平台上的开发实践。
本文所有代码均已在 OpenHarmony 设备上验证通过,项目源码托管于 AtomGit:https://atomgit.com
二、项目架构设计
打车出行应用采用经典的分层架构设计,整体分为数据模型层、服务层和 UI 层三个层次:
- 数据模型层(models):定义车辆类型、司机信息、行程订单、发票等核心数据实体
- 服务层(services):提供模拟数据生成、业务逻辑处理、状态管理等能力
- UI 层(pages):基于 Flutter Material Design 构建用户界面,包含打车首页、价格比较、叫车流程、行程记录、紧急求助等页面
这种分层设计使得代码职责清晰、易于维护,同时也方便后续接入真实后端服务。
三、数据模型设计
首先定义打车应用的核心数据模型。我们使用 Dart 的枚举和类来抽象车辆类型、行程状态、司机信息等业务实体。
enum VehicleType {
economy, // 经济型
comfort, // 舒适型
business, // 商务型
luxury, // 豪华型
carpool, // 拼车
}
enum RideStatus {
searching, // 寻找车辆
matched, // 司机已接单
arrived, // 司机已到达
inProgress, // 行程中
completed, // 已完成
cancelled, // 已取消
}
车辆类型信息使用 VehicleTypeInfo 类封装,包含基础定价策略:
class VehicleTypeInfo {
final VehicleType type;
final String name;
final double basePrice;
final double pricePerKm;
final double pricePerMinute;
const VehicleTypeInfo({
required this.type,
required this.name,
required this.basePrice,
required this.pricePerKm,
required this.pricePerMinute,
});
static const List<VehicleTypeInfo> allTypes = [
VehicleTypeInfo(
type: VehicleType.economy, name: '经济型',
basePrice: 8.0, pricePerKm: 1.6, pricePerMinute: 0.3,
),
VehicleTypeInfo(
type: VehicleType.comfort, name: '舒适型',
basePrice: 12.0, pricePerKm: 2.2, pricePerMinute: 0.4,
),
VehicleTypeInfo(
type: VehicleType.business, name: '商务型',
basePrice: 18.0, pricePerKm: 3.0, pricePerMinute: 0.5,
),
VehicleTypeInfo(
type: VehicleType.luxury, name: '豪华型',
basePrice: 28.0, pricePerKm: 4.5, pricePerMinute: 0.8,
),
VehicleTypeInfo(
type: VehicleType.carpool, name: '拼车',
basePrice: 5.0, pricePerKm: 1.0, pricePerMinute: 0.2,
),
];
}
行程订单模型 RideOrder 记录了完整的行程信息,包括上下车地点、车辆类型、司机信息、费用明细等。通过 copyWith 方法实现不可变对象的状态更新,这是 Flutter 中推荐的做法。
四、服务层实现
服务层采用单例模式,提供模拟数据生成和业务逻辑处理能力。以下是附近车辆搜索的核心实现:
class RideService {
static final RideService _instance = RideService._();
factory RideService() => _instance;
RideService._() {
_initMockDrivers();
_initMockLocations();
}
List<Driver> getNearbyDrivers(
double latitude, double longitude, {
VehicleType? vehicleType,
double radiusKm = 3.0,
}) {
return _drivers.where((d) {
if (!d.isAvailable) return false;
if (vehicleType != null && d.vehicleType != vehicleType) return false;
final distance = _calculateDistance(
latitude, longitude, d.latitude, d.longitude,
);
return distance <= radiusKm;
}).toList();
}
double _calculateDistance(
double lat1, double lng1, double lat2, double lng2,
) {
const r = 6371.0;
final dLat = _toRadians(lat2 - lat1);
final dLng = _toRadians(lng2 - lng1);
final a = sin(dLat / 2) * sin(dLat / 2) +
cos(_toRadians(lat1)) * cos(_toRadians(lat2)) *
sin(dLng / 2) * sin(dLng / 2);
final c = 2 * atan2(sqrt(a), sqrt(1 - a));
return double.parse((r * c).toStringAsFixed(2));
}
}
价格预估功能根据里程和时长计算各车型的预估价格,并支持优惠券抵扣:
List<PriceEstimate> getPriceEstimates(
double distanceKm, int durationMinutes,
) {
return VehicleTypeInfo.allTypes.map((info) {
final price = info.basePrice +
info.pricePerKm * distanceKm +
info.pricePerMinute * durationMinutes;
return PriceEstimate(
vehicleType: info.type,
estimatedPrice: double.parse(price.toStringAsFixed(2)),
estimatedDistance: distanceKm,
estimatedDuration: durationMinutes,
);
}).toList();
}
五、UI 层实现
5.1 打车首页与附近车辆搜索
打车首页是用户进入应用的第一界面,包含上车地点选择、目的地输入、附近车辆展示和快捷操作入口。我们使用 Timer.periodic 实现每 5 秒自动刷新附近车辆列表,模拟实时定位效果。
class _RideHomePageState extends State<RideHomePage> {
final _rideService = RideService();
final _pickupController = TextEditingController();
final _dropoffController = TextEditingController();
RideLocation? _pickupLocation;
RideLocation? _dropoffLocation;
List<Driver> _nearbyDrivers = [];
Timer? _refreshTimer;
void initState() {
super.initState();
_pickupLocation = _rideService.savedLocations.first;
_pickupController.text = _pickupLocation!.name;
_refreshNearbyDrivers();
_refreshTimer = Timer.periodic(
const Duration(seconds: 5), (_) => _refreshNearbyDrivers(),
);
}
void _refreshNearbyDrivers() {
if (_pickupLocation == null) return;
setState(() {
_nearbyDrivers = _rideService.getNearbyDrivers(
_pickupLocation!.latitude,
_pickupLocation!.longitude,
);
});
}
}
地点选择采用底部弹出面板(BottomSheet)的设计,展示常用地点和热门目的地,用户点击即可快速填入。
5.2 价格预估比较
价格预估页面展示五种车型的价格对比,按价格从低到高排序,并标注"最实惠"标签。用户可以选择优惠券进行抵扣,实时查看折后价格。
Widget _buildPriceList(ThemeData theme) {
final sortedEstimates = List<PriceEstimate>.from(_estimates)
..sort((a, b) => a.estimatedPrice.compareTo(b.estimatedPrice));
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: sortedEstimates.length,
itemBuilder: (context, index) {
final estimate = sortedEstimates[index];
final typeInfo = VehicleTypeInfo.getByType(estimate.vehicleType);
final discountedPrice = _getDiscountedPrice(estimate.estimatedPrice);
return Container(
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: index == 0 ? Colors.green : Colors.grey.shade200,
width: index == 0 ? 2 : 1,
),
),
child: ListTile(
leading: Text(typeInfo.icon, style: const TextStyle(fontSize: 28)),
title: Text(typeInfo.name),
subtitle: Text(typeInfo.description),
trailing: Column(
children: [
Text('¥${discountedPrice.toStringAsFixed(2)}',
style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold,
),
),
],
),
onTap: () => _confirmRide(estimate.vehicleType, estimate.estimatedPrice),
),
);
},
);
}
5.3 叫车流程模拟
叫车页面完整模拟了从"寻找车辆"到"行程结束"的完整流程,通过状态机驱动 UI 变化:
// 状态流转:searching -> matched -> arrived -> inProgress -> completed
_statusTimer = Timer(const Duration(seconds: 3), () {
final driver = _rideService.matchDriver(order);
if (driver != null && mounted) {
setState(() {
_matchedDriver = driver;
_status = RideStatus.matched;
_rideService.updateOrderStatus(order.id, RideStatus.matched, driver: driver);
});
// 后续状态依次推进...
}
});
每个状态对应不同的 UI 展示:搜索中显示加载动画和等待时间,已接单展示司机信息和车辆详情,行程中显示安全提示,行程结束后提供评价和开票入口。
5.4 紧急求助功能
紧急求助页面是打车应用安全体系的重要组成部分,提供 SOS 一键报警、行程分享、录音取证、快速拍照等安全功能:
class RideEmergencyPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('紧急求助'),
backgroundColor: Colors.red,
foregroundColor: Colors.white,
),
body: SingleChildScrollView(
child: Column(
children: [
_buildEmergencyBanner(theme),
_buildSOSButton(context, theme),
_buildEmergencyContacts(context, contacts, theme),
_buildSafetyTips(theme),
],
),
),
);
}
}
SOS 按钮采用醒目的红色圆形设计,点击后弹出确认对话框,确认后模拟拨打 110 并通知紧急联系人。同时提供行程分享、录音取证等辅助安全功能,全方位保障用户出行安全。
5.5 行程记录与评价发票
行程记录页面按状态分类展示所有订单,支持查看详情。在行程详情页中,用户可以对司机进行星级评分和标签评价,也可以申请开具电子发票(支持个人和企业两种类型)。
六、在 OpenHarmony 上的运行效果
以下是在 OpenHarmony 设备上运行该打车应用的截图展示:
截图一:打车首页
展示上车地点选择、目的地输入、附近车辆分布和快捷操作入口。顶部显示"打车出行"标题,右侧提供订单查看和紧急求助入口。
截图二:价格预估比较
展示五种车型的价格对比列表,每种车型显示图标、名称、描述和预估价格,最实惠的车型高亮显示。
截图三:叫车流程
展示司机接单后的信息展示界面,包含司机头像、姓名、评分、车牌号、车辆型号和颜色等信息。
截图四:紧急求助
展示 SOS 一键报警按钮、紧急联系人列表和安全提示信息,红色主题设计醒目突出。
截图五:行程记录
展示按状态分类的行程列表,每条记录包含路线信息、费用和状态标签。

七、项目源码
本文完整项目源码已托管至 AtomGit,欢迎访问获取:
https://atomgit.com
项目结构如下:
lib/
├── models/
│ └── ride_model.dart # 打车数据模型
├── services/
│ └── ride_service.dart # 打车服务层
└── pages/
└── ride/
├── ride_home_page.dart # 打车首页
├── ride_price_compare_page.dart # 价格预估
├── ride_booking_page.dart # 叫车流程
├── ride_order_list_page.dart # 行程记录
├── ride_order_detail_page.dart # 行程详情
└── ride_emergency_page.dart # 紧急求助
八、总结
本文详细介绍了如何使用 Flutter 在 OpenHarmony 平台上构建一个功能完整的打车出行应用。通过分层架构设计、数据模型抽象、服务层封装和 Material Design UI 构建,我们实现了附近车辆搜索、价格预估比较、预约叫车、行程记录管理、司机评价、紧急求助等核心功能。
Flutter 优秀的跨平台能力和 OpenHarmony 生态的快速发展,为开发者提供了广阔的应用开发空间。希望本文能为正在探索 Flutter for OpenHarmony 开发的读者提供有价值的参考和指导。
欢迎加入开源鸿蒙跨平台社区,共同推动 OpenHarmony 生态繁荣发展:
https://openharmonycrossplatform.csdn.net
更多推荐

所有评论(0)