Flutter框架跨平台鸿蒙开发——

🚀运行效果展示

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

Flutter框架跨平台鸿蒙开发——二手物品交易APP的开发流程

前言

随着移动互联网的快速发展,跨平台开发技术已经成为移动应用开发的重要趋势。Flutter作为Google推出的开源UI工具包,凭借其"一次编写,多处运行"的优势,已经成为跨平台开发的主流选择。同时,鸿蒙OS作为华为自主研发的分布式操作系统,也在不断发展壮大,为开发者提供了更广阔的应用场景。

本文将详细介绍如何使用Flutter框架开发一款跨平台的二手物品交易APP,并成功运行在鸿蒙OS上。通过本文的学习,读者将了解Flutter跨平台开发的基本流程,以及如何针对鸿蒙OS进行适配和优化。

APP介绍

应用概述

二手物品交易APP是一款为用户提供二手物品买卖服务的移动应用,旨在帮助用户便捷地发布、浏览和购买二手物品,促进资源的循环利用。

核心功能

  • 物品浏览:用户可以浏览平台上的二手物品,查看物品的详细信息。
  • 物品搜索:用户可以通过关键词搜索感兴趣的物品。
  • 分类筛选:用户可以按照物品分类进行筛选,快速找到目标物品。
  • 发布物品:用户可以发布自己的二手物品,包括物品图片、标题、价格、描述等信息。
  • 物品详情:用户可以查看物品的详细信息,包括图片、描述、价格、发布者信息等。
  • 联系卖家:用户可以通过APP联系物品的发布者,进行交易协商。
  • 个人中心:用户可以管理自己发布的物品,查看已售出的物品等。

目标用户

  • 买家:希望以较低价格购买二手物品的用户。
  • 卖家:希望出售闲置物品获取收益的用户。
  • 环保主义者:关注资源循环利用的用户。

开发环境搭建

技术栈选择

  • 前端框架:Flutter 3.0+
  • 开发语言:Dart
  • 状态管理:Provider(本文使用 setState 进行简单状态管理)
  • 网络请求:Dio(本文使用模拟数据)
  • UI组件:Flutter内置组件

环境配置

  1. 安装Flutter SDK:从Flutter官网下载并安装Flutter SDK,配置环境变量。
  2. 安装Dart SDK:Flutter SDK已包含Dart SDK。
  3. 安装IDE:推荐使用Android Studio或VS Code,并安装Flutter和Dart插件。
  4. 配置鸿蒙开发环境:参考华为官方文档,安装DevEco Studio和相关依赖。
  5. 创建Flutter项目:使用flutter create命令创建新项目。

核心功能实现及代码展示

1. 数据模型设计

首先,我们需要设计二手物品的数据模型,定义物品的基本信息结构。

/// 二手物品数据模型
/// 用于存储和管理二手物品的详细信息
class SecondHandItem {
  /// 物品唯一标识符
  final String id;

  /// 物品标题
  final String title;

  /// 物品描述
  final String description;

  /// 物品价格
  final double price;

  /// 物品图片URL
  final String imageUrl;

  /// 物品分类
  final String category;

  /// 发布者ID
  final String publisherId;

  /// 发布者名称
  final String publisherName;

  /// 发布时间
  final DateTime publishTime;

  /// 物品状态(全新、九成新、八成新等)
  final String condition;

  /// 交易地点
  final String location;

  /// 是否已售出
  final bool isSold;

  /// 构造函数
  SecondHandItem({
    required this.id,
    required this.title,
    required this.description,
    required this.price,
    required this.imageUrl,
    required this.category,
    required this.publisherId,
    required this.publisherName,
    required this.publishTime,
    required this.condition,
    required this.location,
    this.isSold = false,
  });

  /// 从JSON创建SecondHandItem实例
  factory SecondHandItem.fromJson(Map<String, dynamic> json) {
    return SecondHandItem(
      id: json['id'],
      title: json['title'],
      description: json['description'],
      price: json['price'],
      imageUrl: json['imageUrl'],
      category: json['category'],
      publisherId: json['publisherId'],
      publisherName: json['publisherName'],
      publishTime: DateTime.parse(json['publishTime']),
      condition: json['condition'],
      location: json['location'],
      isSold: json['isSold'] ?? false,
    );
  }

  /// 转换为JSON格式
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'title': title,
      'description': description,
      'price': price,
      'imageUrl': imageUrl,
      'category': category,
      'publisherId': publisherId,
      'publisherName': publisherName,
      'publishTime': publishTime.toIso8601String(),
      'condition': condition,
      'location': location,
      'isSold': isSold,
    };
  }

  /// 创建副本并更新指定字段
  SecondHandItem copyWith({
    String? id,
    String? title,
    String? description,
    double? price,
    String? imageUrl,
    String? category,
    String? publisherId,
    String? publisherName,
    DateTime? publishTime,
    String? condition,
    String? location,
    bool? isSold,
  }) {
    return SecondHandItem(
      id: id ?? this.id,
      title: title ?? this.title,
      description: description ?? this.description,
      price: price ?? this.price,
      imageUrl: imageUrl ?? this.imageUrl,
      category: category ?? this.category,
      publisherId: publisherId ?? this.publisherId,
      publisherName: publisherName ?? this.publisherName,
      publishTime: publishTime ?? this.publishTime,
      condition: condition ?? this.condition,
      location: location ?? this.location,
      isSold: isSold ?? this.isSold,
    );
  }
}

2. 服务层实现

接下来,我们实现二手物品服务类,用于管理物品数据和相关操作。

/// 二手物品服务类
/// 用于管理二手物品数据和相关操作
import '../models/second_hand_item_model.dart';
import '../utils/mock_data.dart';

class SecondHandItemService {
  /// 获取所有二手物品列表
  Future<List<SecondHandItem>> getItems() async {
    // 模拟网络请求延迟
    await Future.delayed(Duration(milliseconds: 500));

    // 返回模拟数据
    return MockData.secondHandItems;
  }

  /// 根据分类获取物品列表
  Future<List<SecondHandItem>> getItemsByCategory(String category) async {
    await Future.delayed(Duration(milliseconds: 300));

    if (category == '全部') {
      return MockData.secondHandItems;
    }

    return MockData.secondHandItems
        .where((item) => item.category == category)
        .toList();
  }

  /// 根据ID获取物品详情
  Future<SecondHandItem?> getItemById(String id) async {
    await Future.delayed(Duration(milliseconds: 200));

    return MockData.secondHandItems
        .firstWhere((item) => item.id == id, orElse: () => throw Exception('Item not found'));
  }

  /// 发布新物品
  Future<SecondHandItem> publishItem(SecondHandItem item) async {
    await Future.delayed(Duration(milliseconds: 500));

    // 在实际应用中,这里会调用API将物品保存到服务器
    // 这里我们只是将物品添加到模拟数据中
    MockData.secondHandItems.insert(0, item);

    return item;
  }

  /// 搜索物品
  Future<List<SecondHandItem>> searchItems(String keyword) async {
    await Future.delayed(Duration(milliseconds: 300));

    if (keyword.isEmpty) {
      return MockData.secondHandItems;
    }

    return MockData.secondHandItems
        .where((item) =>
            item.title.toLowerCase().contains(keyword.toLowerCase()) ||
            item.description.toLowerCase().contains(keyword.toLowerCase()))
        .toList();
  }

  /// 获取用户发布的物品
  Future<List<SecondHandItem>> getUserItems(String userId) async {
    await Future.delayed(Duration(milliseconds: 300));

    return MockData.secondHandItems
        .where((item) => item.publisherId == userId)
        .toList();
  }

  /// 标记物品为已售出
  Future<void> markAsSold(String itemId) async {
    await Future.delayed(Duration(milliseconds: 200));

    final itemIndex = MockData.secondHandItems
        .indexWhere((item) => item.id == itemId);

    if (itemIndex != -1) {
      final updatedItem = MockData.secondHandItems[itemIndex].copyWith(isSold: true);
      MockData.secondHandItems[itemIndex] = updatedItem;
    }
  }
}

3. 物品列表页面

物品列表页面是APP的核心页面之一,用于展示所有二手物品,并提供搜索和分类筛选功能。

/// 二手物品首页
/// 展示二手物品列表,包含搜索和分类筛选功能
import 'package:flutter/material.dart';
import '../services/second_hand_item_service.dart';
import '../models/second_hand_item_model.dart';
import '../utils/mock_data.dart';
import 'second_hand_detail_page.dart';
import 'second_hand_publish_page.dart';

class SecondHandHomePage extends StatefulWidget {
  
  _SecondHandHomePageState createState() => _SecondHandHomePageState();
}

class _SecondHandHomePageState extends State<SecondHandHomePage> {
  final SecondHandItemService _itemService = SecondHandItemService();
  List<SecondHandItem> _items = [];
  List<SecondHandItem> _filteredItems = [];
  String _selectedCategory = '全部';
  String _searchKeyword = '';
  bool _isLoading = true;
  bool _isRefreshing = false;

  
  void initState() {
    super.initState();
    _loadItems();
  }

  /// 加载物品列表
  Future<void> _loadItems() async {
    setState(() {
      _isLoading = true;
    });

    try {
      final items = await _itemService.getItems();
      setState(() {
        _items = items;
        _filteredItems = items;
        _isLoading = false;
      });
    } catch (error) {
      print('加载物品失败: $error');
      setState(() {
        _isLoading = false;
      });
    }
  }

  /// 刷新物品列表
  Future<void> _refreshItems() async {
    setState(() {
      _isRefreshing = true;
    });

    await _loadItems();

    setState(() {
      _isRefreshing = false;
    });
  }

  /// 筛选物品
  void _filterItems() {
    if (_selectedCategory == '全部' && _searchKeyword.isEmpty) {
      setState(() {
        _filteredItems = _items;
      });
      return;
    }

    List<SecondHandItem> filtered = _items;

    // 按分类筛选
    if (_selectedCategory != '全部') {
      filtered = filtered.where((item) => item.category == _selectedCategory).toList();
    }

    // 按关键词搜索
    if (_searchKeyword.isNotEmpty) {
      filtered = filtered.where((item) =>
          item.title.toLowerCase().contains(_searchKeyword.toLowerCase()) ||
          item.description.toLowerCase().contains(_searchKeyword.toLowerCase())).toList();
    }

    setState(() {
      _filteredItems = filtered;
    });
  }

  /// 处理分类选择
  void _handleCategorySelect(String category) {
    setState(() {
      _selectedCategory = category;
    });
    _filterItems();
  }

  /// 处理搜索提交
  void _handleSearchSubmit(String keyword) {
    setState(() {
      _searchKeyword = keyword;
    });
    _filterItems();
  }

  /// 导航到物品详情页
  void _navigateToDetail(String itemId) {
    Navigator.pushNamed(
      context,
      '/second_hand_detail',
      arguments: itemId,
    );
  }

  /// 导航到发布物品页
  void _navigateToPublish() {
    Navigator.pushNamed(
      context,
      '/second_hand_publish',
    ).then((_) => _loadItems()); // 发布完成后刷新列表
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('二手物品交易'),
        actions: [
          IconButton(
            icon: Icon(Icons.person),
            onPressed: () {
              // 导航到个人中心
              Navigator.pushNamed(context, '/second_hand_profile');
            },
          ),
        ],
      ),
      body: Column(
        children: [
          // 搜索栏
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              decoration: InputDecoration(
                hintText: '搜索物品...',
                prefixIcon: Icon(Icons.search),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(20),
                ),
                contentPadding: EdgeInsets.symmetric(vertical: 8),
              ),
              onSubmitted: _handleSearchSubmit,
            ),
          ),

          // 分类筛选栏
          Container(
            height: 50,
            child: ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: MockData.secondHandCategories.length,
              itemBuilder: (context, index) {
                final category = MockData.secondHandCategories[index];
                return Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
                  child: ChoiceChip(
                    label: Text(category),
                    selected: _selectedCategory == category,
                    onSelected: (_) => _handleCategorySelect(category),
                    selectedColor: Colors.blue,
                    labelStyle: TextStyle(
                      color: _selectedCategory == category ? Colors.white : Colors.black,
                    ),
                  ),
                );
              },
            ),
          ),

          // 物品列表
          Expanded(
            child: _isLoading
                ? Center(child: CircularProgressIndicator())
                : RefreshIndicator(
                    onRefresh: _refreshItems,
                    child: _filteredItems.isEmpty
                        ? Center(child: Text('暂无物品'))
                        : ListView.builder(
                            itemCount: _filteredItems.length,
                            itemBuilder: (context, index) {
                              final item = _filteredItems[index];
                              return _buildItemCard(item);
                            },
                          ),
                  ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _navigateToPublish,
        child: Icon(Icons.add),
        tooltip: '发布物品',
      ),
    );
  }

  /// 构建物品卡片
  Widget _buildItemCard(SecondHandItem item) {
    return Card(
      margin: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      elevation: 3,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(12),
      ),
      child: InkWell(
        onTap: () => _navigateToDetail(item.id),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // 物品图片
            Container(
              width: 100,
              height: 100,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.only(
                  topLeft: Radius.circular(12),
                  bottomLeft: Radius.circular(12),
                ),
                image: DecorationImage(
                  image: AssetImage(item.imageUrl),
                  fit: BoxFit.cover,
                ),
              ),
            ),

            // 物品信息
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(12.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    // 标题和价格
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Expanded(
                          child: Text(
                            item.title,
                            style: TextStyle(
                              fontSize: 16,
                              fontWeight: FontWeight.bold,
                            ),
                            maxLines: 1,
                            overflow: TextOverflow.ellipsis,
                          ),
                        ),
                        SizedBox(width: 8),
                        Text(
                          ${item.price}',
                          style: TextStyle(
                            fontSize: 16,
                            fontWeight: FontWeight.bold,
                            color: Colors.red,
                          ),
                        ),
                      ],
                    ),

                    // 描述
                    SizedBox(height: 4),
                    Text(
                      item.description,
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.grey[600],
                      ),
                      maxLines: 2,
                      overflow: TextOverflow.ellipsis,
                    ),

                    // 其他信息
                    SizedBox(height: 8),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Row(
                          children: [
                            Text(
                              item.condition,
                              style: TextStyle(
                                fontSize: 12,
                                color: Colors.grey[500],
                              ),
                            ),
                            SizedBox(width: 12),
                            Text(
                              item.location,
                              style: TextStyle(
                                fontSize: 12,
                                color: Colors.grey[500],
                              ),
                            ),
                          ],
                        ),
                        Text(
                          '${item.publisherName}',
                          style: TextStyle(
                            fontSize: 12,
                            color: Colors.grey[500],
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

4. 物品详情页面

物品详情页面用于展示物品的详细信息,包括图片、描述、价格、发布者信息等,并提供联系卖家的功能。

/// 二手物品详情页
/// 展示二手物品的详细信息,包括图片、描述、价格等
import 'package:flutter/material.dart';
import '../services/second_hand_item_service.dart';
import '../models/second_hand_item_model.dart';

class SecondHandDetailPage extends StatefulWidget {
  final String itemId;

  const SecondHandDetailPage({Key? key, required this.itemId}) : super(key: key);

  
  _SecondHandDetailPageState createState() => _SecondHandDetailPageState();
}

class _SecondHandDetailPageState extends State<SecondHandDetailPage> {
  final SecondHandItemService _itemService = SecondHandItemService();
  SecondHandItem? _item;
  bool _isLoading = true;
  bool _isError = false;
  String _errorMessage = '';

  
  void initState() {
    super.initState();
    _loadItemDetail();
  }

  /// 加载物品详情
  Future<void> _loadItemDetail() async {
    setState(() {
      _isLoading = true;
      _isError = false;
    });

    try {
      final item = await _itemService.getItemById(widget.itemId);
      setState(() {
        _item = item;
        _isLoading = false;
      });
    } catch (error) {
      print('加载物品详情失败: $error');
      setState(() {
        _isError = true;
        _errorMessage = '加载失败,请重试';
        _isLoading = false;
      });
    }
  }

  /// 联系发布者
  void _contactPublisher() {
    if (_item == null) return;

    // 在实际应用中,这里会跳转到聊天页面或显示联系方式
    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: Text('联系卖家'),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text('卖家: ${_item!.publisherName}'),
              SizedBox(height: 8),
              Text('物品: ${_item!.title}'),
              SizedBox(height: 8),
              Text('价格: ¥${_item!.price}'),
              SizedBox(height: 16),
              Text('联系方式将通过系统消息发送给您'),
            ],
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: Text('取消'),
            ),
            TextButton(
              onPressed: () {
                Navigator.pop(context);
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text('联系信息已发送')),
                );
              },
              child: Text('确定'),
            ),
          ],
        );
      },
    );
  }

  /// 分享物品
  void _shareItem() {
    if (_item == null) return;

    // 在实际应用中,这里会调用系统分享功能
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('分享功能已触发')),
    );
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('物品详情'),
        actions: [
          IconButton(
            icon: Icon(Icons.share),
            onPressed: _shareItem,
            tooltip: '分享',
          ),
        ],
      ),
      body: _isLoading
          ? Center(child: CircularProgressIndicator())
          : _isError
              ? Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(_errorMessage),
                      SizedBox(height: 16),
                      ElevatedButton(
                        onPressed: _loadItemDetail,
                        child: Text('重试'),
                      ),
                    ],
                  ),
                )
              : _item == null
                  ? Center(child: Text('物品不存在'))
                  : _buildDetailContent(),
      bottomNavigationBar: _item != null ? _buildBottomBar() : null,
    );
  }

  /// 构建详情内容
  Widget _buildDetailContent() {
    if (_item == null) return Container();

    return SingleChildScrollView(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // 物品图片
          Container(
            width: double.infinity,
            height: 300,
            decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage(_item!.imageUrl),
                fit: BoxFit.cover,
              ),
            ),
          ),

          // 物品信息
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                // 标题和价格
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Expanded(
                      child: Text(
                        _item!.title,
                        style: TextStyle(
                          fontSize: 20,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                    Text(
                      ${_item!.price}',
                      style: TextStyle(
                        fontSize: 24,
                        fontWeight: FontWeight.bold,
                        color: Colors.red,
                      ),
                    ),
                  ],
                ),

                // 物品状态和交易地点
                SizedBox(height: 12),
                Row(
                  children: [
                    Container(
                      padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4),
                      decoration: BoxDecoration(
                        color: Colors.grey[200],
                        borderRadius: BorderRadius.circular(12),
                      ),
                      child: Text(
                        _item!.condition,
                        style: TextStyle(
                          fontSize: 14,
                          color: Colors.grey[700],
                        ),
                      ),
                    ),
                    SizedBox(width: 16),
                    Icon(Icons.location_on, size: 16, color: Colors.grey[600]),
                    SizedBox(width: 4),
                    Text(
                      _item!.location,
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.grey[600],
                      ),
                    ),
                  ],
                ),

                // 发布时间
                SizedBox(height: 8),
                Text(
                  '发布时间: ${_formatDateTime(_item!.publishTime)}',
                  style: TextStyle(
                    fontSize: 12,
                    color: Colors.grey[500],
                  ),
                ),

                // 描述
                SizedBox(height: 20),
                Text(
                  '物品描述',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                SizedBox(height: 8),
                Text(
                  _item!.description,
                  style: TextStyle(
                    fontSize: 14,
                    height: 1.5,
                    color: Colors.grey[800],
                  ),
                ),

                // 发布者信息
                SizedBox(height: 24),
                Container(
                  padding: EdgeInsets.all(16),
                  decoration: BoxDecoration(
                    color: Colors.grey[50],
                    borderRadius: BorderRadius.circular(12),
                  ),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        '发布者信息',
                        style: TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      SizedBox(height: 12),
                      Row(
                        children: [
                          // 发布者头像(这里使用默认头像)
                          Container(
                            width: 50,
                            height: 50,
                            decoration: BoxDecoration(
                              shape: BoxShape.circle,
                              color: Colors.grey[300],
                            ),
                            child: Center(
                              child: Text(
                                _item!.publisherName.substring(0, 1),
                                style: TextStyle(
                                  fontSize: 20,
                                  fontWeight: FontWeight.bold,
                                  color: Colors.grey[600],
                                ),
                              ),
                            ),
                          ),
                          SizedBox(width: 16),
                          Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                _item!.publisherName,
                                style: TextStyle(
                                  fontSize: 16,
                                  fontWeight: FontWeight.w500,
                                ),
                              ),
                              SizedBox(height: 4),
                              Text(
                                '查看主页',
                                style: TextStyle(
                                  fontSize: 14,
                                  color: Colors.blue,
                                ),
                              ),
                            ],
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),

          // 底部空间,确保内容不被底部导航栏遮挡
          SizedBox(height: 80),
        ],
      ),
    );
  }

  /// 构建底部导航栏
  Widget _buildBottomBar() {
    if (_item == null) return Container();

    return Container(
      padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
      decoration: BoxDecoration(
        border: Border(top: BorderSide(color: Colors.grey[200]!)),
        color: Colors.white,
      ),
      child: Row(
        children: [
          Expanded(
            child: ElevatedButton(
              onPressed: _contactPublisher,
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.blue,
                padding: EdgeInsets.symmetric(vertical: 14),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(8),
                ),
              ),
              child: Text(
                '联系卖家',
                style: TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  /// 格式化日期时间
  String _formatDateTime(DateTime dateTime) {
    final now = DateTime.now();
    final difference = now.difference(dateTime);

    if (difference.inDays > 0) {
      return '${difference.inDays}天前';
    } else if (difference.inHours > 0) {
      return '${difference.inHours}小时前';
    } else if (difference.inMinutes > 0) {
      return '${difference.inMinutes}分钟前';
    } else {
      return '刚刚';
    }
  }
}

5. 发布物品页面

发布物品页面用于用户发布新的二手物品,包括填写物品信息、上传图片等功能。

/// 发布二手物品页面
/// 用于用户发布新的二手物品
import 'package:flutter/material.dart';
import '../services/second_hand_item_service.dart';
import '../models/second_hand_item_model.dart';
import '../utils/mock_data.dart';

class SecondHandPublishPage extends StatefulWidget {
  
  _SecondHandPublishPageState createState() => _SecondHandPublishPageState();
}

class _SecondHandPublishPageState extends State<SecondHandPublishPage> {
  final SecondHandItemService _itemService = SecondHandItemService();
  final _formKey = GlobalKey<FormState>();
  
  // 表单字段
  String _title = '';
  String _description = '';
  double _price = 0.0;
  String _category = MockData.secondHandCategories[1]; // 默认选择第一个分类
  String _condition = '九成新'; // 默认选择九成新
  String _location = '';
  String _imageUrl = 'images/R-C.jpg'; // 默认图片
  
  bool _isSubmitting = false;

  // 物品状态选项
  final List<String> _conditionOptions = [
    '全新',
    '九成新',
    '八成新',
    '七成新',
    '六成新',
    '五成新及以下',
  ];

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('发布二手物品'),
      ),
      body: SingleChildScrollView(
        padding: EdgeInsets.all(16),
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              // 图片上传
              Container(
                width: double.infinity,
                height: 200,
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey[300]!),
                  borderRadius: BorderRadius.circular(8),
                  image: DecorationImage(
                    image: AssetImage(_imageUrl),
                    fit: BoxFit.cover,
                  ),
                ),
                child: Center(
                  child: ElevatedButton(
                    onPressed: _selectImage,
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.black.withOpacity(0.5),
                    ),
                    child: Text('更换图片'),
                  ),
                ),
              ),
              SizedBox(height: 20),

              // 标题
              TextFormField(
                decoration: InputDecoration(
                  labelText: '物品标题',
                  hintText: '请输入物品标题',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                  ),
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return '请输入物品标题';
                  }
                  if (value.length > 50) {
                    return '标题长度不能超过50个字符';
                  }
                  return null;
                },
                onSaved: (value) => _title = value!,
              ),
              SizedBox(height: 16),

              // 价格
              TextFormField(
                decoration: InputDecoration(
                  labelText: '物品价格',
                  hintText: '请输入物品价格',
                  prefixText: '¥',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                  ),
                ),
                keyboardType: TextInputType.numberWithOptions(decimal: true),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return '请输入物品价格';
                  }
                  final price = double.tryParse(value);
                  if (price == null || price <= 0) {
                    return '请输入有效的价格';
                  }
                  return null;
                },
                onSaved: (value) => _price = double.parse(value!),
              ),
              SizedBox(height: 16),

              // 分类
              DropdownButtonFormField<String>(
                decoration: InputDecoration(
                  labelText: '物品分类',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                  ),
                ),
                value: _category,
                items: MockData.secondHandCategories.skip(1).map((category) {
                  return DropdownMenuItem(
                    value: category,
                    child: Text(category),
                  );
                }).toList(),
                onChanged: (value) {
                  setState(() {
                    _category = value!;
                  });
                },
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return '请选择物品分类';
                  }
                  return null;
                },
              ),
              SizedBox(height: 16),

              // 物品状态
              DropdownButtonFormField<String>(
                decoration: InputDecoration(
                  labelText: '物品状态',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                  ),
                ),
                value: _condition,
                items: _conditionOptions.map((condition) {
                  return DropdownMenuItem(
                    value: condition,
                    child: Text(condition),
                  );
                }).toList(),
                onChanged: (value) {
                  setState(() {
                    _condition = value!;
                  });
                },
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return '请选择物品状态';
                  }
                  return null;
                },
              ),
              SizedBox(height: 16),

              // 交易地点
              TextFormField(
                decoration: InputDecoration(
                  labelText: '交易地点',
                  hintText: '请输入交易地点',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                  ),
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return '请输入交易地点';
                  }
                  return null;
                },
                onSaved: (value) => _location = value!,
              ),
              SizedBox(height: 16),

              // 描述
              TextFormField(
                decoration: InputDecoration(
                  labelText: '物品描述',
                  hintText: '请详细描述物品的成色、使用情况等信息',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                  ),
                  alignLabelWithHint: true,
                ),
                maxLines: 4,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return '请输入物品描述';
                  }
                  if (value.length < 10) {
                    return '描述长度不能少于10个字符';
                  }
                  if (value.length > 500) {
                    return '描述长度不能超过500个字符';
                  }
                  return null;
                },
                onSaved: (value) => _description = value!,
              ),
              SizedBox(height: 32),

              // 发布按钮
              SizedBox(
                width: double.infinity,
                child: ElevatedButton(
                  onPressed: _submitForm,
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.blue,
                    padding: EdgeInsets.symmetric(vertical: 16),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(8),
                    ),
                  ),
                  child: _isSubmitting
                      ? SizedBox(
                          height: 20,
                          width: 20,
                          child: CircularProgressIndicator(
                            strokeWidth: 2,
                            valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
                          ),
                        )
                      : Text(
                          '发布物品',
                          style: TextStyle(
                            fontSize: 16,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                ),
              ),
              SizedBox(height: 32),
            ],
          ),
        ),
      ),
    );
  }

  /// 选择图片
  void _selectImage() {
    // 在实际应用中,这里会调用系统相册或相机
    // 这里我们只是模拟更换图片
    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: Text('选择图片'),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              GestureDetector(
                onTap: () {
                  setState(() {
                    _imageUrl = 'images/R-C.jpg';
                  });
                  Navigator.pop(context);
                },
                child: Container(
                  width: 100,
                  height: 100,
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: AssetImage('images/R-C.jpg'),
                      fit: BoxFit.cover,
                    ),
                  ),
                ),
              ),
              SizedBox(height: 16),
              GestureDetector(
                onTap: () {
                  setState(() {
                    _imageUrl = 'images/u=174051936,621369760&fm=253&gp=0.jpg';
                  });
                  Navigator.pop(context);
                },
                child: Container(
                  width: 100,
                  height: 100,
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: AssetImage('images/u=174051936,621369760&fm=253&gp=0.jpg'),
                      fit: BoxFit.cover,
                    ),
                  ),
                ),
              ),
              SizedBox(height: 16),
              GestureDetector(
                onTap: () {
                  setState(() {
                    _imageUrl = 'images/1687770031227597.png';
                  });
                  Navigator.pop(context);
                },
                child: Container(
                  width: 100,
                  height: 100,
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: AssetImage('images/1687770031227597.png'),
                      fit: BoxFit.cover,
                    ),
                  ),
                ),
              ),
            ],
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: Text('取消'),
            ),
          ],
        );
      },
    );
  }

  /// 提交表单
  void _submitForm() {
    if (_formKey.currentState!.validate()) {
      _formKey.currentState!.save();
      _publishItem();
    }
  }

  /// 发布物品
  Future<void> _publishItem() async {
    setState(() {
      _isSubmitting = true;
    });

    try {
      final item = SecondHandItem(
        id: DateTime.now().millisecondsSinceEpoch.toString(),
        title: _title,
        description: _description,
        price: _price,
        imageUrl: _imageUrl,
        category: _category,
        publisherId: 'current_user', // 实际应用中应该使用当前登录用户的ID
        publisherName: '当前用户', // 实际应用中应该使用当前登录用户的名称
        publishTime: DateTime.now(),
        condition: _condition,
        location: _location,
        isSold: false,
      );

      await _itemService.publishItem(item);

      // 发布成功,返回上一页
      Navigator.pop(context, true);
    } catch (error) {
      print('发布物品失败: $error');
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('发布失败,请重试')),
      );
    } finally {
      setState(() {
        _isSubmitting = false;
      });
    }
  }
}

6. 个人中心页面

个人中心页面用于展示用户信息,管理用户发布的物品,以及提供其他功能入口。

/// 个人中心页面
/// 展示用户信息和相关操作
import 'package:flutter/material.dart';
import '../services/second_hand_item_service.dart';
import '../models/second_hand_item_model.dart';
import 'second_hand_detail_page.dart';
import 'second_hand_publish_page.dart';

class SecondHandProfilePage extends StatefulWidget {
  
  _SecondHandProfilePageState createState() => _SecondHandProfilePageState();
}

class _SecondHandProfilePageState extends State<SecondHandProfilePage> {
  final SecondHandItemService _itemService = SecondHandItemService();
  List<SecondHandItem> _myItems = [];
  List<SecondHandItem> _soldItems = [];
  bool _isLoading = true;

  
  void initState() {
    super.initState();
    _loadMyItems();
  }

  /// 加载用户发布的物品
  Future<void> _loadMyItems() async {
    setState(() {
      _isLoading = true;
    });

    try {
      // 模拟获取当前用户ID
      final currentUserId = 'current_user';
      final items = await _itemService.getUserItems(currentUserId);
      
      // 分离已售出和未售出的物品
      final myItems = items.where((item) => !item.isSold).toList();
      final soldItems = items.where((item) => item.isSold).toList();

      setState(() {
        _myItems = myItems;
        _soldItems = soldItems;
        _isLoading = false;
      });
    } catch (error) {
      print('加载用户物品失败: $error');
      setState(() {
        _isLoading = false;
      });
    }
  }

  /// 标记物品为已售出
  Future<void> _markAsSold(String itemId) async {
    try {
      await _itemService.markAsSold(itemId);
      await _loadMyItems();
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('物品已标记为已售出')),
      );
    } catch (error) {
      print('标记物品失败: $error');
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('操作失败,请重试')),
      );
    }
  }

  /// 导航到物品详情页
  void _navigateToDetail(String itemId) {
    Navigator.pushNamed(
      context,
      '/second_hand_detail',
      arguments: itemId,
    );
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('个人中心'),
      ),
      body: _isLoading
          ? Center(child: CircularProgressIndicator())
          : SingleChildScrollView(
              child: Column(
                children: [
                  // 用户信息卡片
                  _buildUserInfoCard(),
                  
                  // 功能菜单
                  _buildFunctionMenu(),
                  
                  // 我的发布
                  _buildMyItemsSection(),
                  
                  // 已售出
                  _buildSoldItemsSection(),
                ],
              ),
            ),
    );
  }

  /// 构建用户信息卡片
  Widget _buildUserInfoCard() {
    return Container(
      padding: EdgeInsets.all(20),
      color: Colors.blue,
      child: Row(
        children: [
          // 用户头像
          Container(
            width: 80,
            height: 80,
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: Colors.white,
            ),
            child: Center(
              child: Text(
                '用',
                style: TextStyle(
                  fontSize: 32,
                  fontWeight: FontWeight.bold,
                  color: Colors.blue,
                ),
              ),
            ),
          ),
          
          SizedBox(width: 20),
          
          // 用户信息
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                '当前用户',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                  color: Colors.white,
                ),
              ),
              SizedBox(height: 8),
              Text(
                'ID: current_user',
                style: TextStyle(
                  fontSize: 14,
                  color: Colors.white.withOpacity(0.8),
                ),
              ),
              SizedBox(height: 4),
              Text(
                '注册时间: 2024-01-01',
                style: TextStyle(
                  fontSize: 14,
                  color: Colors.white.withOpacity(0.8),
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }

  /// 构建功能菜单
  Widget _buildFunctionMenu() {
    return Container(
      margin: EdgeInsets.symmetric(vertical: 16),
      padding: EdgeInsets.symmetric(horizontal: 16),
      child: GridView.count(
        crossAxisCount: 4,
        shrinkWrap: true,
        physics: NeverScrollableScrollPhysics(),
        children: [
          _buildMenuItem(Icons.add_circle, '发布物品', () {
            Navigator.pushNamed(
              context,
              '/second_hand_publish',
            ).then((_) => _loadMyItems());
          }),
          _buildMenuItem(Icons.favorite, '我的收藏', () {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('收藏功能开发中')),
            );
          }),
          _buildMenuItem(Icons.chat, '我的消息', () {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('消息功能开发中')),
            );
          }),
          _buildMenuItem(Icons.settings, '设置', () {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('设置功能开发中')),
            );
          }),
        ],
      ),
    );
  }

  /// 构建菜单项
  Widget _buildMenuItem(IconData icon, String title, VoidCallback onTap) {
    return GestureDetector(
      onTap: onTap,
      child: Column(
        children: [
          Container(
            width: 60,
            height: 60,
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: Colors.grey[100],
            ),
            child: Icon(icon, size: 28, color: Colors.blue),
          ),
          SizedBox(height: 8),
          Text(
            title,
            style: TextStyle(fontSize: 12),
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }

  /// 构建我的发布部分
  Widget _buildMyItemsSection() {
    return Container(
      margin: EdgeInsets.symmetric(vertical: 16),
      padding: EdgeInsets.symmetric(horizontal: 16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(
                '我的发布',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              TextButton(
                onPressed: () {
                  Navigator.pushNamed(
                    context,
                    '/second_hand_publish',
                  ).then((_) => _loadMyItems());
                },
                child: Text('发布新物品'),
              ),
            ],
          ),
          
          if (_myItems.isEmpty)
            Padding(
              padding: EdgeInsets.symmetric(vertical: 20),
              child: Text('暂无发布物品'),
            )
          else
            Column(
              children: _myItems.map((item) => _buildItemCard(item, true)).toList(),
            ),
        ],
      ),
    );
  }

  /// 构建已售出部分
  Widget _buildSoldItemsSection() {
    return Container(
      margin: EdgeInsets.symmetric(vertical: 16),
      padding: EdgeInsets.symmetric(horizontal: 16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            '已售出',
            style: TextStyle(
              fontSize: 18,
              fontWeight: FontWeight.bold,
            ),
          ),
          
          if (_soldItems.isEmpty)
            Padding(
              padding: EdgeInsets.symmetric(vertical: 20),
              child: Text('暂无已售出物品'),
            )
          else
            Column(
              children: _soldItems.map((item) => _buildItemCard(item, false)).toList(),
            ),
        ],
      ),
    );
  }

  /// 构建物品卡片
  Widget _buildItemCard(SecondHandItem item, bool showMarkAsSold) {
    return Card(
      margin: EdgeInsets.symmetric(vertical: 8),
      elevation: 2,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(8),
      ),
      child: InkWell(
        onTap: () => _navigateToDetail(item.id),
        child: Padding(
          padding: EdgeInsets.all(12),
          child: Row(
            children: [
              // 物品图片
              Container(
                width: 80,
                height: 80,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(8),
                  image: DecorationImage(
                    image: AssetImage(item.imageUrl),
                    fit: BoxFit.cover,
                  ),
                ),
              ),
              
              SizedBox(width: 12),
              
              // 物品信息
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      item.title,
                      style: TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                      maxLines: 1,
                      overflow: TextOverflow.ellipsis,
                    ),
                    
                    SizedBox(height: 4),
                    
                    Text(
                      ${item.price}',
                      style: TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                        color: Colors.red,
                      ),
                    ),
                    
                    SizedBox(height: 4),
                    
                    Text(
                      item.condition,
                      style: TextStyle(
                        fontSize: 12,
                        color: Colors.grey[600],
                      ),
                    ),
                  ],
                ),
              ),
              
              // 操作按钮
              if (showMarkAsSold)
                IconButton(
                  onPressed: () => _markAsSold(item.id),
                  icon: Icon(Icons.check_circle_outline),
                  tooltip: '标记为已售出',
                ),
            ],
          ),
        ),
      ),
    );
  }
}

7. 路由配置

最后,我们需要在main.dart文件中配置APP的路由,确保各个页面之间能够正确导航。

/// 应用入口文件
/// 配置应用路由和主题
import 'package:flutter/material.dart';
import 'pages/second_hand_home_page.dart';
import 'pages/second_hand_detail_page.dart';
import 'pages/second_hand_publish_page.dart';
import 'pages/second_hand_profile_page.dart';

void main() {
  runApp(const MyApp());
}

/// 应用主类
class MyApp extends StatelessWidget {
  /// 构造函数
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '二手物品交易',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: SecondHandHomePage(),
      routes: {
        '/second_hand_detail': (context) => SecondHandDetailPage(
              itemId: ModalRoute.of(context)?.settings.arguments as String,
            ),
        '/second_hand_publish': (context) => SecondHandPublishPage(),
        '/second_hand_profile': (context) => SecondHandProfilePage(),
      },
      debugShowCheckedModeBanner: false,
    );
  }
}

开发流程总结

开发过程中遇到的问题及解决方案

  1. 跨平台适配问题

    • 问题:Flutter在不同平台上的渲染效果存在差异,特别是在鸿蒙OS上。
    • 解决方案:使用Flutter的LayoutBuilder和MediaQuery组件,根据不同屏幕尺寸和平台进行适配。
  2. 图片加载优化

    • 问题:大量图片加载导致APP性能下降。
    • 解决方案:使用缓存策略,延迟加载不在可视区域内的图片,优化图片大小和格式。
  3. 状态管理复杂性

    • 问题:随着功能的增加,状态管理变得越来越复杂。
    • 解决方案:对于复杂应用,建议使用Provider、Bloc等状态管理库,提高代码可维护性。
  4. 网络请求处理

    • 问题:网络请求失败时的错误处理和用户体验。
    • 解决方案:实现统一的网络请求封装,添加加载状态、错误状态和重试机制。

性能优化措施

  1. UI优化

    • 使用const构造函数创建不可变widget。
    • 避免在build方法中执行耗时操作。
    • 使用ListView.builder等懒加载组件。
  2. 内存优化

    • 及时释放不再使用的资源。
    • 使用WeakReference管理大对象。
    • 避免内存泄漏。
  3. 网络优化

    • 实现请求缓存。
    • 使用合适的网络请求库,如Dio。
    • 优化API设计,减少不必要的网络请求。

测试和部署

  1. 测试

    • 单元测试:测试各个功能模块的逻辑。
    • 集成测试:测试多个模块之间的交互。
    • UI测试:测试用户界面的渲染和交互。
    • 性能测试:测试APP的性能表现。
  2. 部署

    • 鸿蒙OS:生成HAP包,通过AppGallery Connect发布。
    • Android:生成APK或AAB包,通过Google Play发布。
    • iOS:生成IPA包,通过App Store发布。

未来展望

功能扩展计划

  1. 实时聊天功能:实现买家和卖家之间的实时沟通。
  2. 支付功能:集成第三方支付平台,实现线上交易。
  3. 评价系统:建立买卖双方的评价机制,提高交易可信度。
  4. 物流跟踪:对于需要邮寄的物品,提供物流跟踪功能。
  5. 推荐系统:根据用户的浏览和购买历史,推荐相关物品。

技术升级方向

  1. 使用Flutter 3.0+的新特性:如Impeller渲染引擎,提高APP性能。
  2. 采用更先进的状态管理方案:如Riverpod、Bloc等。
  3. 集成机器学习:实现更智能的物品推荐和搜索。
  4. 使用Flutter Web:扩展到Web平台,实现全平台覆盖。
  5. 优化鸿蒙OS特有功能:充分利用鸿蒙OS的分布式能力。

总结

通过本文的介绍,我们详细了解了如何使用Flutter框架开发一款跨平台的二手物品交易APP,并成功运行在鸿蒙OS上。从数据模型设计到页面实现,从功能开发到测试部署,我们完整地展示了整个开发流程。

Flutter作为一款优秀的跨平台开发框架,不仅可以大幅提高开发效率,还能保证APP在不同平台上的一致性和性能。而鸿蒙OS作为一款新兴的分布式操作系统,为开发者提供了更广阔的应用场景和创新空间。

二手物品交易APP的开发过程中,我们注重用户体验和功能完整性,同时也关注性能优化和代码质量。通过合理的架构设计和技术选型,我们成功构建了一款功能完善、性能良好的跨平台应用。

未来,随着Flutter和鸿蒙OS的不断发展,我们可以期待开发出更多优秀的跨平台应用,为用户带来更好的使用体验。同时,我们也将继续探索新的技术和方法,不断提升自己的开发能力和产品质量。


附录:项目结构

lib/
├── models/
│   └── second_hand_item_model.dart  // 二手物品数据模型
├── services/
│   └── second_hand_item_service.dart  // 二手物品服务
├── utils/
│   └── mock_data.dart  // 模拟数据
├── pages/
│   ├── second_hand_home_page.dart  // 物品列表页面
│   ├── second_hand_detail_page.dart  // 物品详情页面
│   ├── second_hand_publish_page.dart  // 发布物品页面
│   └── second_hand_profile_page.dart  // 个人中心页面
└── main.dart  // 应用入口和路由配置

📚 参考资料

  1. Flutter官方文档
  2. HarmonyOS开发者文档
  3. Flutter for HarmonyOS

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐