# flutter_page_flip **Repository Path**: kayouyou/flutter_page_flip ## Basic Information - **Project Name**: flutter_page_flip - **Description**: No description available - **Primary Language**: Dart - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2025-06-24 - **Last Updated**: 2025-07-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Flutter Page Flip 一个高性能的Flutter翻页动画组件,支持多种翻页效果、手势控制、页面复用和内存优化。 ![Flutter](https://img.shields.io/badge/Flutter-02569B?style=for-the-badge&logo=flutter&logoColor=white) ![Dart](https://img.shields.io/badge/Dart-0175C2?style=for-the-badge&logo=dart&logoColor=white) ## ✨ 核心功能 ### 🎨 多种翻页动画 - **Cover**: 覆盖效果,简洁流畅 ✅ **推荐使用**(经过充分验证) - **Curl**: 卷曲效果,模拟真实翻页 ⚠️ **Beta功能** - **Flip**: 翻转效果,3D立体感 ⚠️ **Beta功能** - **Simulation**: 仿真效果,物理模拟 ⚠️ **Beta功能** - **Simulation2**: 增强仿真,更丰富的视觉效果 ⚠️ **Beta功能** > 💡 **重要提示**: 目前只有 `PageFlipAnimation.cover` 经过充分测试验证,建议生产环境使用。其他动画效果为开发阶段的Beta功能,可能存在性能或兼容性问题,不建议在正式项目中使用。 ### 🎯 智能交互 - **手势控制**: 支持滑动翻页,可配置敏感度 - **双向拖拽**: 🆕 支持中途改变拖拽方向,界面真实跟随手指 - **点击翻页**: 可选的左右点击区域翻页 - **键盘控制**: 方向键、Home/End键导航 - **触摸反馈**: 实时动画反馈 ### ⚡ 高性能优化 - **3容器复用**: 只使用3个页面容器处理任意数量页面 - **内存高效**: 固定内存占用,不随页面数量增长 - **大页面支持**: 轻松处理100+页面 - **流畅动画**: 60FPS动画性能 ### 🔧 灵活配置 - **敏感度调节**: 可配置翻页触发阈值 - **动画时长**: 自定义动画持续时间 - **交互模式**: 多种交互模式选择 - **单手模式**: 左右点击行为反转 ## 📦 安装 在你的 `pubspec.yaml` 文件中添加依赖: ```yaml dependencies: flutter_page_flip: ^1.0.1 ``` 或者从 GitHub 安装: ```yaml dependencies: flutter_page_flip: git: url: https://github.com/your-username/flutter_page_flip.git ref: v1.0.1 ``` 然后运行: ```bash flutter pub get ``` ## 🚀 快速开始 ```dart import 'package:flutter/material.dart'; import 'package:flutter_page_flip/flutter_page_flip.dart'; class MyPageFlipWidget extends StatefulWidget { @override _MyPageFlipWidgetState createState() => _MyPageFlipWidgetState(); } class _MyPageFlipWidgetState extends State with TickerProviderStateMixin { late PageFlipController _controller; @override void initState() { super.initState(); _controller = PageFlipController( config: const PageFlipConfig( // 基础配置 animation: PageFlipAnimation.cover, // 推荐使用cover动画 animationDuration: 300, enableGestures: true, enableTapToFlip: true, // 翻页敏感度配置 flipVelocityThreshold: 600.0, // 速度阈值 flipDistanceThreshold: 0.35, // 距离阈值(35%) ), pageCount: 100, pageBuilder: (index) => Container( color: Colors.primaries[index % Colors.primaries.length], child: Center( child: Text( '第 ${index + 1} 页', style: const TextStyle(fontSize: 24, color: Colors.white), ), ), ), onPageChanged: (index) { print('切换到第 ${index + 1} 页'); }, ); _controller.initAnimationControllers(this); } @override Widget build(BuildContext context) { return Scaffold( body: PageFlipWidget(controller: _controller), ); } @override void dispose() { _controller.dispose(); super.dispose(); } } ``` ## 🏗️ 架构设计 ### 核心组件架构 ```mermaid graph TB A[PageFlipWidget] --> B[PageFlipController] B --> C[PageContainerManager] B --> D[AnimationController x3] C --> E[Container 0
前一页] C --> F[Container 1
当前页] C --> G[Container 2
下一页] H[手势检测] --> B I[键盘事件] --> B J[点击事件] --> B B --> K[页面切换回调] ``` ### 3容器复用机制 本组件的核心创新是使用3容器循环复用机制,无论有多少页面,始终只使用3个容器: ```mermaid graph LR A[容器0: 前一页] --> B[容器1: 当前页] --> C[容器2: 下一页] C --> A D[页面映射表] D --> A D --> B D --> C ``` #### 容器映射示例 | 当前页 | 容器0 | 容器1 | 容器2 | 说明 | |--------|--------|--------|--------|------| | 第1页 | - | 第1页 | 第2页 | 首页无前一页 | | 第5页 | 第4页 | 第5页 | 第6页 | 正常情况 | | 第100页| 第99页 | 第100页| - | 末页无下一页 | ## 🔄 底层实现细节 ### 手势处理流程 ```mermaid flowchart TD A[用户开始滑动] --> B[检测滑动方向] B --> C[左滑:下一页
右滑:上一页] C --> D[累积滑动距离] D --> E[计算动画进度] E --> F[实时更新容器动画值] F --> G[用户松手] G --> H{翻页判断} H -->|是| I[完成翻页动画] H -->|否| J[恢复原状态] I --> K[更新页面索引] K --> L[重新映射容器] L --> M[触发页面变化回调] J --> N[重置动画状态] ``` ### 翻页判断逻辑 翻页触发需满足以下任一条件: ```dart final shouldFlip = velocity > config.flipVelocityThreshold || // 速度条件 controller.value < (1.0 - config.flipDistanceThreshold); // 距离条件 ``` #### 具体计算过程 1. **距离计算**: ```dart // 累积滑动距离 _accumulatedDrag += primaryDelta.abs(); // 计算滑动进度 (0.0 - 1.0) final dragProgress = (_accumulatedDrag / screenWidth).clamp(0.0, 1.0); // 动画值:1.0(隐藏) -> 0.0(显示) final animationValue = (1.0 - dragProgress).clamp(0.0, 1.0); ``` 2. **判断条件**: - **速度条件**: `velocity > 600.0` (默认) - **距离条件**: `animationValue < 0.65` (即滑动35%时) ### 动画状态管理 每个容器都有独立的动画控制器: - **值 = 0.0**: 容器完全显示 - **值 = 1.0**: 容器完全隐藏 - **值 0.0-1.0**: 容器处于动画过渡状态 ## 🔧 核心类架构说明 ### 主要组件类 #### 📱 PageFlipWidget **主要UI组件,负责渲染和交互处理** ```dart class PageFlipWidget extends StatefulWidget ``` **核心功能:** - 🎯 **UI渲染管理** - 管理3个PageContainer的显示层级和动画效果 - 🖱️ **手势处理** - 监听和处理水平拖拽、点击等用户交互 - ⌨️ **键盘控制** - 响应方向键、Home/End等键盘事件 - 🎨 **动画效果** - 根据配置应用不同的翻页动画(cover、curl、flip等) - 📱 **系统UI** - 管理状态栏、导航栏的显示状态 - 🍔 **菜单系统** - 处理中心区域的菜单显示和隐藏 **关键方法:** - `_updatePageContainers()` - 更新页面容器映射关系 - `_buildInteractivePageLayers()` - 构建交互模式的页面层级 - `_buildCurrentPageSlideOut()` - 构建当前页滑出动画效果 #### 🎮 PageFlipController **核心控制器,管理翻页逻辑和状态** ```dart class PageFlipController extends ChangeNotifier ``` **核心功能:** - 📊 **状态管理** - 维护当前页面索引、动画状态、页面总数等 - 🎯 **页面导航** - 提供nextPage()、previousPage()、goToPage()等导航方法 - 🎬 **动画控制** - 管理3个AnimationController,控制翻页动画 - 🖱️ **手势响应** - 处理拖拽开始、更新、结束的完整手势流程 - ⚡ **敏感度控制** - 根据配置判断是否触发翻页(速度/距离阈值) - 🔄 **容器管理** - 通过PageContainerManager协调容器复用 **关键方法:** - `handleDragUpdate()` - 处理手势拖拽过程中的动画更新 - `handleDragEnd()` - 处理手势结束时的翻页判断 - `_animateToAdjacentPage()` - 执行相邻页面的平滑动画 - `_shouldFlipPage()` - 根据速度和距离判断是否执行翻页 #### 📦 PageContainer **页面内容容器,负责单页面的渲染和缓存** ```dart class PageContainer extends StatefulWidget ``` **核心功能:** - 🎨 **页面构建** - 通过pageBuilder构建具体的页面内容 - 💾 **内容缓存** - 缓存已构建的页面Widget,避免重复构建 - 🔄 **状态管理** - 响应页面索引变化,自动更新显示内容 - ❌ **错误处理** - 页面构建失败时显示友好的错误页面 - ⚡ **性能优化** - 只在页面索引真正变化时才重新构建内容 **关键方法:** - `didUpdateWidget()` - 响应Widget参数变化 - `_buildPageIfNeeded()` - 按需构建页面内容 - `_buildErrorPage()` - 构建错误页面 #### 🗂️ PageContainerManager **容器映射管理器,实现3容器复用逻辑** ```dart class PageContainerManager ``` **核心功能:** - 🔄 **容器映射** - 维护页面索引到容器ID的映射关系 - 📊 **状态同步** - 根据当前页面索引更新所有容器的页面分配 - 🎯 **查询接口** - 提供页面索引↔容器ID的双向查询 - ⚡ **内存优化** - 确保固定使用3个容器,不随页面数量增长 **容器分配规则:** ```dart // 容器0:前一页 (currentIndex - 1) // 容器1:当前页 (currentIndex) // 容器2:下一页 (currentIndex + 1) ``` **关键方法:** - `setCurrentPageIndex()` - 设置当前页并更新容器映射 - `getContainerPageIndex()` - 获取指定容器应显示的页面索引 - `getContainerIdForPage()` - 获取指定页面对应的容器ID #### ⚙️ PageFlipConfig **配置类,定义组件的各种行为参数** ```dart class PageFlipConfig ``` **配置分类:** 🎨 **动画配置** - `animation` - 翻页动画类型(cover/curl/flip/simulation等) - `animationDuration` - 动画持续时间 - `interactionMode` - 交互模式(interactive/picture/auto) 🖱️ **交互配置** - `enableGestures` - 是否启用手势控制 - `enableTapToFlip` - 是否启用点击翻页 - `enableKeyboard` - 是否启用键盘控制 - `oneHandMode` - 单手模式(反转左右点击) ⚡ **敏感度配置** - `flipVelocityThreshold` - 翻页速度阈值(px/s) - `flipDistanceThreshold` - 翻页距离阈值(0.0-1.0) 🎨 **视觉配置** - `backgroundColor` - 背景颜色 - `showStatus` - 是否显示状态栏 - `menuZoneRatio` - 菜单区域比例 ### 数据流向图 ```mermaid flowchart TD A[用户交互] --> B[PageFlipWidget] B --> C[PageFlipController] C --> D[PageContainerManager] D --> E[更新容器映射] E --> F[PageContainer更新] F --> G[页面重新渲染] C --> H[动画控制器] H --> I[实时动画更新] I --> B J[PageFlipConfig] --> C J --> B ``` ### 类关系总结 | 类名 | 职责 | 依赖关系 | |------|------|----------| | **PageFlipWidget** | UI渲染与交互 | 依赖Controller、使用Container | | **PageFlipController** | 逻辑控制中心 | 管理Manager、控制Animation | | **PageContainer** | 页面内容管理 | 被Widget使用,独立运行 | | **PageContainerManager** | 容器映射管理 | 被Controller管理 | | **PageFlipConfig** | 配置参数 | 被Widget和Controller使用 | **🔑 核心设计理念:** - **职责分离** - 每个类专注特定功能,降低耦合度 - **3容器复用** - 固定内存占用,支持无限页面 - **配置驱动** - 通过配置灵活控制行为 - **性能优先** - 缓存机制和复用策略确保流畅体验 ### 🚀 预创建机制详解 #### 预加载时机流程图 ``` 用户操作:第99页 → 第100页 → 向左滑动显示第101页 时刻1: 用户在第99页 ┌─────────┬─────────┬─────────┐ │ 容器0 │ 容器1 │ 容器2 │ │ 第98页 │ 第99页 │ 第100页 │ ← 第100页已预创建 └─────────┴─────────┴─────────┘ 时刻2: 用户滑动到第100页(🎯 第101页创建时机) ┌─────────┬─────────┬─────────┐ │ 容器0 │ 容器1 │ 容器2 │ │ 第99页 │ 第100页 │ 第101页 │ ← 🔥 第101页在此时创建! └─────────┴─────────┴─────────┘ 时刻3: 用户向左滑动显示第101页 ┌─────────┬─────────┬─────────┐ │ 容器0 │ 容器1 │ 容器2 │ │ 第99页 │ 第100页 │ 第101页 │ ← 第101页已存在,只需动画显示 └─────────┴─────────┴─────────┘ ``` #### 预创建代码实现 **1. 容器映射更新触发** ```dart // 📁 lib/src/page_flip_controller.dart Future handleDragEnd(DragEndDetails details) async { // 滑动结束,更新页面索引 _currentIndex = targetIndex; // 更新到第100页 _containerManager.setCurrentPageIndex(_currentIndex); // 🎯 触发预创建 _onPageChanged?.call(_currentIndex); notifyListeners(); } ``` **2. 容器映射自动分配** ```dart // 📁 lib/src/page_container.dart void setCurrentPageIndex(int index) { _currentPageIndex = index; // 设置为第100页 _updateContainerMapping(); // 🎯 自动分配容器 } void _updateContainerMapping() { // 自动为相邻页面分配容器 _containerPageIndexes[0] = _currentPageIndex > 0 ? _currentPageIndex - 1 : null; // 容器0 → 第99页 _containerPageIndexes[1] = _currentPageIndex; // 容器1 → 第100页 _containerPageIndexes[2] = _currentPageIndex < pageCount - 1 ? _currentPageIndex + 1 : null; // 🎯 容器2 → 第101页(预创建) } ``` **3. 容器内容构建** ```dart // 📁 lib/src/page_flip_widget.dart void _updatePageContainers() { for (int i = 0; i < _pageContainers.length; i++) { final newPageIndex = widget.controller.containerManager.getContainerPageIndex(i); // 检查是否需要更新容器内容 if (currentContainer.currentPageIndex != newPageIndex) { // 🎯 创建新容器显示第101页 _pageContainers[i] = PageContainer( currentPageIndex: newPageIndex, // 第101页 pageBuilder: widget.controller.pageBuilder, onPageBuilt: () => setState(() {}), // 构建完成回调 ); } } } ``` **4. 页面内容实际构建** ```dart // 📁 lib/src/page_container.dart void _buildPageIfNeeded() { if (widget.currentPageIndex != null && widget.currentPageIndex != _cachedPageIndex) { // 🎯 调用pageBuilder创建第101页的实际内容 _cachedPage = widget.pageBuilder(widget.currentPageIndex!); _cachedPageIndex = widget.currentPageIndex; // 异步通知构建完成 WidgetsBinding.instance.addPostFrameCallback((_) { widget.onPageBuilt?.call(); }); } } ``` #### 性能优势 ✅ **无滑动卡顿**: 滑动时只需动画显示已创建的页面 ✅ **内存固定**: 始终只有3个页面在内存中 ✅ **响应迅速**: 预创建确保瞬时响应 ✅ **异步构建**: 页面构建不阻塞UI线程 #### 调试信息 在开发模式下,可以看到详细的预创建日志: ``` 🔧 开始更新页面容器... 🔧 容器2: 当前页面100 -> 新页面101 🔧 重新创建容器2,页面索引: 100 -> 101 🔧 容器2页面构建完成,显示页面101 🔧 页面容器更新完成 ``` ### 🔄 数据刷新最佳实践 由于预创建机制会缓存页面Widget,如果页面数据发生变化,推荐使用状态管理方案: #### 使用 BLoC 状态管理(推荐) ```dart // 页面构建器使用BLoC pageBuilder: (index) { return BlocProvider( create: (context) => PageBloc()..add(LoadPageEvent(index)), child: BlocBuilder( builder: (context, state) { if (state is PageLoaded) { return YourPageWidget(data: state.data); // 数据变化时自动重建 } return LoadingWidget(); }, ), ); } // 在其他地方更新数据时 context.read().add(RefreshPageEvent()); // 自动触发页面重建 ``` #### 使用 Provider 状态管理 ```dart pageBuilder: (index) { return ChangeNotifierProvider( create: (_) => PageModel(index), child: Consumer( builder: (context, model, child) { return YourPageWidget(data: model.data); // 数据变化时自动重建 }, ), ); } ``` #### 优势对比 | 方案 | 优势 | 适用场景 | |------|------|----------| | **状态管理** | 🎯 无需修改翻页组件
🔄 自动响应数据变化
📱 标准Flutter模式 | 复杂数据流、实时更新 | | **手动刷新** | 🎮 直接控制
⚡ 性能可控 | 简单场景、手动触发 | **💡 建议**:对于动态数据场景,使用 BLoC 或 Provider 等状态管理方案,让页面内部自动响应数据变化,无需修改翻页组件本身。 ## 📋 配置参数详解 | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `animation` | `PageFlipAnimation` | `cover` | 翻页动画类型(推荐使用cover) | | `animationDuration` | `int` | `300` | 动画持续时间(毫秒) | | `backgroundColor` | `Color` | `Colors.white` | 背景颜色 | | `enableGestures` | `bool` | `true` | 是否启用手势控制 | | `enableKeyboard` | `bool` | `true` | 是否启用键盘控制 | | `enableTapToFlip` | `bool` | `true` | 是否启用点击翻页 | | `oneHandMode` | `bool` | `false` | 单手模式(反转左右点击) | | `menuZoneRatio` | `double` | `0.33` | 菜单区域比例 | | `showStatus` | `bool` | `true` | 是否显示状态栏 | | `animationStatus` | `bool` | `false` | 动画时是否显示状态栏 | | `interactionMode` | `PageFlipInteractionMode` | `auto` | 交互模式 | | `flipVelocityThreshold` | `double` | `600.0` | 翻页速度阈值(px/s) | | `flipDistanceThreshold` | `double` | `0.35` | 翻页距离阈值(0.0-1.0) | ### 敏感度调节示例 ```dart // 高敏感度设置 - 更容易翻页 PageFlipConfig( flipVelocityThreshold: 300.0, // 更低的速度要求 flipDistanceThreshold: 0.20, // 滑动20%就能翻页 ) // 低敏感度设置 - 需要更明确的翻页意图 PageFlipConfig( flipVelocityThreshold: 1000.0, // 更高的速度要求 flipDistanceThreshold: 0.50, // 需要滑动50%才能翻页 ) ``` ## 🎮 控制器方法 ```dart // 基础导航 await controller.nextPage(); // 下一页 await controller.previousPage(); // 上一页 await controller.goToPage(10); // 跳转到第11页 // 状态查询 int currentPage = controller.currentIndex; // 当前页面索引 bool isFirst = controller.isFirstPage; // 是否首页 bool isLast = controller.isLastPage; // 是否末页 bool animating = controller.isAnimating; // 是否正在动画 // 动画控制 AnimationController? animCtrl = controller.getAnimationController(pageIndex); ``` ## 🔧 高级用法 ### 自定义动画效果 ⚠️ **注意**: 建议生产环境使用 `PageFlipAnimation.cover`,其他动画为Beta功能。 ```dart PageFlipConfig( animation: PageFlipAnimation.cover, // 推荐:稳定的覆盖效果 // animation: PageFlipAnimation.curl, // ⚠️ Beta功能,不建议生产使用 animationDuration: 500, // 更慢的动画 flipVelocityThreshold: 200.0, // 很容易触发的速度 flipDistanceThreshold: 0.15, // 滑动15%就翻页 ) ``` ### 性能优化建议 1. **大量页面处理**: ```dart // ✅ 推荐:使用延迟构建 pageBuilder: (index) { return Builder( builder: (context) => ExpensivePage(index: index), ); } ``` 2. **内存使用**: - 3容器机制确保固定内存占用 - 无需担心页面数量对内存的影响 ## 📱 示例应用 查看 `example/` 目录获取完整示例,包含: - ✅ **基础翻页**: 简单的页面翻页效果 - ✅ **随机跳转**: 测试大范围页面跳转 - ✅ **敏感度测试**: 不同触发阈值的体验 - ✅ **多种动画**: 各种翻页动画效果对比 ## 🤝 贡献指南 欢迎贡献代码!请遵循以下步骤: 1. Fork 本仓库 2. 创建功能分支 (`git checkout -b feature/amazing-feature`) 3. 提交更改 (`git commit -m 'Add amazing feature'`) 4. 推送到分支 (`git push origin feature/amazing-feature`) 5. 开启 Pull Request ## 📄 许可证 本项目基于 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。 ## 🎯 核心优势总结 | 传统方案 | Flutter Page Flip | |----------|-------------------| | 每页一个Widget实例 | 3容器循环复用 | | 内存随页面数增长 | 固定内存占用 | | 预加载复杂管理 | 自动容器管理 | | 性能随页面数下降 | 稳定高性能 | | 滑动时创建页面 | 预创建机制 | | 可能出现卡顿 | 流畅无卡顿 | ### 🚀 预创建机制优势 **传统翻页方案的问题:** - 📱 滑动时才创建新页面 → 可能卡顿 - 💾 每页都保持在内存中 → 内存占用过高 - 🔄 复杂的页面生命周期管理 → 容易出错 **Flutter Page Flip的解决方案:** - ⚡ **预创建**: 下一页在当前页显示时就已创建完成 - 🎯 **3容器复用**: 无论多少页面,内存中始终只有3个页面 - 🔄 **自动管理**: 容器自动分配,无需手动管理页面生命周期 - 🎪 **动画流畅**: 滑动时只是动画显示,不涉及页面创建 **实际效果对比:** ``` 传统方案: 用户滑动 → 创建新页面 → 可能卡顿 → 显示页面 Flutter Page Flip: 用户滑动 → 动画显示已创建页面 → 流畅无卡顿 ``` **3容器复用 + 预创建机制确保无论是10页还是1000页,都能保持相同的流畅性能!** 🚀 ## 📈 版本历史 ### v1.0.1 (2024-01-XX) 🔥 重要更新 - 🚀 **手势交互重大优化**: - 修复左滑后右滑不跟随的问题 - 支持拖拽过程中改变方向 - 界面真实跟随手指移动 - 更符合用户直觉的滑动体验 - 🔧 **技术改进**: - 使用净位移替代累积绝对值 - 实时方向检测算法 - 优化手势生命周期管理 - 移除方向锁定限制 - ✨ **用户体验提升**: - 支持中途改变滑动方向 - 平滑的双向拖拽响应 - 更自然的手势交互 ### v1.0.0 (2024-01-XX) - 🎉 **首个正式版本发布** - ✨ **核心功能**: - 3容器复用机制 - 预创建优化 - 多种翻页动画效果 - 完整的手势控制 - 键盘导航支持 - 📚 **文档完善**: - 详细的架构说明 - 预创建机制解析 - 数据刷新最佳实践 - 性能优化指南 - 🔧 **开发工具**: - 完整的示例代码 - 性能测试工具 - 调试日志支持 ## 🏷️ 版本兼容性 | Flutter版本 | 兼容性 | 说明 | |-------------|--------|------| | 3.0.0+ | ✅ 完全支持 | 推荐版本 | | 2.5.0+ | ✅ 支持 | 基础功能可用 | | 2.0.0+ | ⚠️ 部分支持 | 部分功能可能受限 | ## 🔗 相关链接 - 📖 [API文档](https://pub.dev/documentation/flutter_page_flip/latest/) - 🐛 [问题反馈](https://github.com/your-username/flutter_page_flip/issues) - 💡 [功能建议](https://github.com/your-username/flutter_page_flip/discussions) - 🌟 [示例项目](https://github.com/your-username/flutter_page_flip/tree/main/example)