在这里插入图片描述

一、核心功能与关键代码讲解

1. 数据模型定义

首先定义MovieCategory两个核心数据模型,承载影视信息与分类信息,采用required关键字保证字段完整性,适配Flutter的空安全规范。

/// 影视数据模型
class Movie {
  int id;
  String title;
  double rating;
  int releaseYear;
  String genre;
  // 其他核心字段(导演、演员等)
  
  Movie({
    required this.id,
    required this.title,
    required this.rating,
    required this.releaseYear,
    required this.genre,
  });
}

/// 分类数据模型
class Category {
  String id;
  String name;
  IconData icon;

  Category({
    required this.id,
    required this.name,
    required this.icon,
  });
}

2. 模拟数据加载

模拟网络请求延迟,生成包含影视类型、评分、年份的测试数据,满足界面展示与功能调试需求,无需依赖真实接口。

// 加载影视数据(含延迟模拟)
Future<void> _loadMovies() async {
  setState(() => _isLoading = true);
  // 模拟1秒网络请求延迟
  await Future.delayed(const Duration(seconds: 1));
  // 生成20条模拟影视数据
  final movies = _generateMockMovies(20);
  setState(() {
    _movies = movies;
    _isLoading = false;
  });
}

// 生成模拟数据核心逻辑
List<Movie> _generateMockMovies(int count) {
  final genres = ["动作", "喜剧", "科幻", "恐怖", "爱情"];
  final random = Random();
  final movies = <Movie>[];
  
  for (int i = 1; i <= count; i++) {
    final genre = genres[random.nextInt(genres.length)];
    movies.add(Movie(
      id: i,
      title: "${genre}电影 ${i}",
      rating: 3.0 + random.nextDouble() * 2.0,
      releaseYear: 2010 + random.nextInt(16),
      genre: genre,
    ));
  }
  return movies;
}

3. 核心交互功能(搜索+分类过滤)

实现搜索关键字过滤与分类切换过滤,组合得到最终展示的影视列表,保证界面数据与用户操作同步。

// 搜索框内容变更回调
void _searchMovies(String keyword) {
  setState(() => _searchKeyword = keyword);
}

// 分类切换回调
void _switchCategory(String categoryId) {
  setState(() => _selectedCategory = categoryId);
}

// 组合过滤:分类+搜索
List<Movie> get _filteredMovies {
  return _movies.where((movie) {
    // 分类过滤逻辑
    bool categoryMatch = _selectedCategory == "all" || 
        (_selectedCategory == "movie" && movie.genre != "电视剧") ||
        (_selectedCategory == "anime" && movie.genre == "动画");
    
    // 搜索过滤逻辑(忽略大小写)
    bool searchMatch = _searchKeyword.isEmpty ||
        movie.title.toLowerCase().contains(_searchKeyword.toLowerCase()) ||
        movie.genre.toLowerCase().contains(_searchKeyword.toLowerCase());
    
    return categoryMatch && searchMatch;
  }).toList();
}

4. 影视卡片UI构建

构建带海报、评分、年份的影视卡片,处理图片加载失败的兜底展示,提升界面美观度与用户体验。

Widget _buildMovieCard(Movie movie) {
  return Container(
    width: 150,
    margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 12),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // 影视海报+评分+年份布局
        Container(
          height: 200,
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(8),
            boxShadow: [BoxShadow(color: Colors.black45, blurRadius: 8)],
          ),
          child: Stack(
            children: [
              // 网络图片+兜底展示
              ClipRRect(
                borderRadius: BorderRadius.circular(8),
                child: Image.network(
                  movie.image,
                  fit: BoxFit.cover,
                  errorBuilder: (context, error, stackTrace) {
                    return Container(
                      color: Colors.grey.shade800,
                      child: const Icon(Icons.movie, size: 48, color: Colors.grey.shade600),
                    );
                  },
                ),
              ),
              // 评分标签(右上角)
              Positioned(
                top: 8, right: 8,
                child: Container(
                  padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                  decoration: BoxDecoration(
                    color: Colors.red.withOpacity(0.9),
                    borderRadius: BorderRadius.circular(12),
                  ),
                  child: Text("${movie.rating.toStringAsFixed(1)}", style: const TextStyle(color: Colors.white)),
                ),
              ),
            ],
          ),
        ),
        // 影视标题与类型
        const SizedBox(height: 10),
        Text(movie.title, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold), maxLines: 2),
      ],
    ),
  );
}

5. 状态兜底展示

处理加载中与空数据状态,避免界面空白,提升用户体验,这是应用骨架的重要组成部分。

// 加载中状态
Widget _buildLoadingState() {
  return Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
      CircularProgressIndicator(color: Colors.red),
      const SizedBox(height: 16),
      const Text("加载中...", style: TextStyle(color: Colors.grey.shade400)),
    ],
  );
}

// 空数据状态
Widget _buildEmptyState() {
  return Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
      const Icon(Icons.movie_filter, size: 64, color: Colors.grey.shade700),
      const SizedBox(height: 16),
      Text(_searchKeyword.isEmpty ? "暂无影视内容" : "没有找到相关影视", style: const TextStyle(color: Colors.grey.shade400)),
    ],
  );
}

二、总结与扩展

本次实现的影视大全骨架,完成了数据模型、模拟加载、交互过滤、UI展示、状态兜底五大核心模块,代码简洁可复用,可直接在HarmonyOS设备上运行调试。

后续可扩展方向:1. 对接真实影视接口,替换模拟数据;2. 增加影视详情页跳转;3. 优化分类导航与列表的滚动交互;4. 添加收藏、筛选等进阶功能。

总结

  1. 核心是先定义数据模型,再实现数据加载与过滤,最后完成UI与兜底状态搭建,遵循"数据先行,UI后置"的开发逻辑。
  2. 交互功能通过setState更新状态,保证界面与数据同步,是Flutter基础开发的核心要点。
  3. 兜底状态(加载中、空数据)是提升用户体验的关键,不可省略。

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

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐