# 主页诗词卡片骨架屏实现计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 修复主页诗词卡片点击下一条时的闪白问题,使用骨架屏实现平滑过渡 **Architecture:** 修改 PoetryCard 组件,在加载新数据时显示骨架屏动画,保持卡片容器不销毁重建,分区域逐步显示内容 **Tech Stack:** Flutter, GetX, Shimmer 效果 --- ## 文件结构 | 文件 | 职责 | |------|------| | `lib/views/home/home_part.dart` | 修改 PoetryCard 组件,添加骨架屏支持 | | `lib/views/home/set/home_components.dart` | 添加骨架屏 Widget 组件 | | `lib/services/get/home_controller.dart` | 调整加载状态管理(如有需要) | --- ## Task 1: 创建骨架屏组件 **Files:** - Create: `lib/views/home/components/skeleton_widgets.dart` - [ ] **Step 1: 创建骨架屏基础组件** ```dart import 'package:flutter/material.dart'; /// 骨架屏基础组件 class SkeletonContainer extends StatefulWidget { final double width; final double height; final double borderRadius; final Color? baseColor; final Color? highlightColor; const SkeletonContainer({ super.key, required this.width, required this.height, this.borderRadius = 8, this.baseColor, this.highlightColor, }); @override State createState() => _SkeletonContainerState(); } class _SkeletonContainerState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _animation; @override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(milliseconds: 1500), vsync: this, )..repeat(); _animation = Tween(begin: -1, end: 2).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOutSine), ); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { return Container( width: widget.width, height: widget.height, decoration: BoxDecoration( borderRadius: BorderRadius.circular(widget.borderRadius), gradient: LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ widget.baseColor ?? Colors.grey[300]!, widget.highlightColor ?? Colors.grey[100]!, widget.baseColor ?? Colors.grey[300]!, ], stops: [ _animation.value - 0.3, _animation.value, _animation.value + 0.3, ], ), ), ); }, ); } } ``` - [ ] **Step 2: 提交代码** ```bash git add lib/views/home/components/skeleton_widgets.dart git commit -m "feat: 添加骨架屏基础组件 SkeletonContainer" ``` --- ## Task 2: 修改 PoetryCard 组件 **Files:** - Modify: `lib/views/home/home_part.dart` - [ ] **Step 1: 导入骨架屏组件** 在文件顶部添加导入: ```dart import 'components/skeleton_widgets.dart'; ``` - [ ] **Step 2: 修改 _buildTitleSection 方法** 找到 `_buildTitleSection` 方法,修改加载状态的显示逻辑: ```dart Widget _buildTitleSection() { final isLoading = widget.sectionLoadingStates?['title'] ?? false; if (isLoading) { return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: SkeletonContainer( width: double.infinity, height: 24, borderRadius: 4, baseColor: widget.isDark ? Colors.grey[800] : Colors.grey[300], highlightColor: widget.isDark ? Colors.grey[700] : Colors.grey[100], ), ); } // 原有的非加载状态代码保持不变 // ... } ``` - [ ] **Step 3: 修改 _buildNameSection 方法** ```dart Widget _buildNameSection() { final isLoading = widget.sectionLoadingStates?['name'] ?? false; if (isLoading) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Column( children: [ SkeletonContainer( width: 120, height: 28, borderRadius: 4, baseColor: widget.isDark ? Colors.grey[800] : Colors.grey[300], highlightColor: widget.isDark ? Colors.grey[700] : Colors.grey[100], ), const SizedBox(height: 8), SkeletonContainer( width: 80, height: 16, borderRadius: 4, baseColor: widget.isDark ? Colors.grey[800] : Colors.grey[300], highlightColor: widget.isDark ? Colors.grey[700] : Colors.grey[100], ), ], ), ); } // 原有的非加载状态代码保持不变 // ... } ``` - [ ] **Step 4: 修改 _buildContentSection 方法** ```dart Widget _buildContentSection() { final isLoading = widget.sectionLoadingStates?['content'] ?? false; if (isLoading) { return Padding( padding: const EdgeInsets.all(16), child: Column( children: List.generate(4, (index) => Padding( padding: const EdgeInsets.only(bottom: 8), child: SkeletonContainer( width: index == 3 ? double.infinity * 0.6 : double.infinity, height: 20, borderRadius: 4, baseColor: widget.isDark ? Colors.grey[800] : Colors.grey[300], highlightColor: widget.isDark ? Colors.grey[700] : Colors.grey[100], ), )), ), ); } // 原有的非加载状态代码保持不变 // ... } ``` - [ ] **Step 5: 修改 _buildKeywordsSection 方法** ```dart Widget _buildKeywordsSection() { final isLoading = widget.sectionLoadingStates?['keywords'] ?? false; if (isLoading) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Wrap( spacing: 8, runSpacing: 8, children: List.generate(3, (index) => SkeletonContainer( width: 60, height: 24, borderRadius: 12, baseColor: widget.isDark ? Colors.grey[800] : Colors.grey[300], highlightColor: widget.isDark ? Colors.grey[700] : Colors.grey[100], )), ), ); } // 原有的非加载状态代码保持不变 // ... } ``` - [ ] **Step 6: 修改 _buildIntroductionSection 方法** ```dart Widget _buildIntroductionSection() { final isLoading = widget.sectionLoadingStates?['introduction'] ?? false; if (isLoading) { return Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SkeletonContainer( width: 80, height: 18, borderRadius: 4, baseColor: widget.isDark ? Colors.grey[800] : Colors.grey[300], highlightColor: widget.isDark ? Colors.grey[700] : Colors.grey[100], ), const SizedBox(height: 12), ...List.generate(3, (index) => Padding( padding: const EdgeInsets.only(bottom: 8), child: SkeletonContainer( width: double.infinity, height: 16, borderRadius: 4, baseColor: widget.isDark ? Colors.grey[800] : Colors.grey[300], highlightColor: widget.isDark ? Colors.grey[700] : Colors.grey[100], ), )), ], ), ); } // 原有的非加载状态代码保持不变 // ... } ``` - [ ] **Step 7: 提交代码** ```bash git add lib/views/home/home_part.dart git commit -m "feat: PoetryCard 组件添加骨架屏支持,修复闪白问题" ``` --- ## Task 3: 测试验证 **Files:** - Test: 运行应用验证 - [ ] **Step 1: 运行 Flutter 分析** ```bash flutter analyze lib/views/home/home_part.dart lib/views/home/components/skeleton_widgets.dart ``` Expected: 无错误 - [ ] **Step 2: 测试功能** 1. 打开主页 2. 点击"下一条"按钮 3. 验证: - 卡片不出现闪白 - 各区域显示骨架屏动画 - 内容加载完成后平滑显示 - 深色模式下骨架屏颜色正确 - [ ] **Step 3: 提交代码** ```bash git add . git commit -m "test: 验证骨架屏功能正常" ``` --- ## 实现要点总结 1. **骨架屏动画**:使用渐变动画实现脉冲效果 2. **深色模式支持**:根据 `isDark` 参数调整骨架屏颜色 3. **分区域加载**:每个区域独立控制骨架屏显示 4. **平滑过渡**:骨架屏到实际内容的切换无闪烁