Flutter PageView 页面视图深度解析:从基础到高级

通过丰富的图表、对比分析和实际案例,全面掌握 Flutter PageView 的使用技巧

📊 文章概览

章节 内容 难度等级
[基础 PageView](#章节 内容 难度等级 基础 PageView 基础页面视图实现 ⭐⭐ PageView.builder 动态页面构建 ⭐⭐⭐ PageController 控制 页面控制器使用 ⭐⭐⭐ 高级特性 高级功能实现 ⭐⭐⭐⭐ 实际应用场景 真实项目案例 ⭐⭐⭐⭐ "#%E5%9F%BA%E7%A1%80-pageview") 基础页面视图实现 ⭐⭐
[PageView.builder](#章节 内容 难度等级 基础 PageView 基础页面视图实现 ⭐⭐ PageView.builder 动态页面构建 ⭐⭐⭐ PageController 控制 页面控制器使用 ⭐⭐⭐ 高级特性 高级功能实现 ⭐⭐⭐⭐ 实际应用场景 真实项目案例 ⭐⭐⭐⭐ "#pageviewbuilder") 动态页面构建 ⭐⭐⭐
[PageController 控制](#章节 内容 难度等级 基础 PageView 基础页面视图实现 ⭐⭐ PageView.builder 动态页面构建 ⭐⭐⭐ PageController 控制 页面控制器使用 ⭐⭐⭐ 高级特性 高级功能实现 ⭐⭐⭐⭐ 实际应用场景 真实项目案例 ⭐⭐⭐⭐ "#pagecontroller-%E6%8E%A7%E5%88%B6") 页面控制器使用 ⭐⭐⭐
[高级特性](#章节 内容 难度等级 基础 PageView 基础页面视图实现 ⭐⭐ PageView.builder 动态页面构建 ⭐⭐⭐ PageController 控制 页面控制器使用 ⭐⭐⭐ 高级特性 高级功能实现 ⭐⭐⭐⭐ 实际应用场景 真实项目案例 ⭐⭐⭐⭐ "#%E9%AB%98%E7%BA%A7%E7%89%B9%E6%80%A7") 高级功能实现 ⭐⭐⭐⭐
[实际应用场景](#章节 内容 难度等级 基础 PageView 基础页面视图实现 ⭐⭐ PageView.builder 动态页面构建 ⭐⭐⭐ PageController 控制 页面控制器使用 ⭐⭐⭐ 高级特性 高级功能实现 ⭐⭐⭐⭐ 实际应用场景 真实项目案例 ⭐⭐⭐⭐ "#%E5%AE%9E%E9%99%85%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF") 真实项目案例 ⭐⭐⭐⭐

🎯 学习目标

  • ✅ 掌握 PageView 的核心概念和使用方法
  • ✅ 学会 PageController 的配置和控制
  • ✅ 理解页面切换动画和手势处理
  • ✅ 能够实现复杂的页面视图应用
  • ✅ 掌握性能优化和最佳实践

📋 目录导航

🎯 快速导航

  • [基础 PageView](#基础 PageView "#%E5%9F%BA%E7%A1%80-pageview") - 基础页面视图实现
  • PageView.builder - 动态页面构建
  • [PageController 控制](#PageController 控制 "#pagecontroller-%E6%8E%A7%E5%88%B6") - 页面控制器使用
  • 高级特性 - 高级功能实现
  • 实际应用场景 - 真实项目案例
  • 性能优化 - 最佳实践

📋 概述

PageView 是 Flutter 中用于实现页面滑动切换的重要控件,支持水平和垂直方向的页面切换,常用于引导页、轮播图、图片浏览等场景。

🏗️ PageView 架构图

graph TD A[Flutter PageView System] --> B[PageView Container] A --> C[PageController] A --> D[Page Management] A --> E[Gesture Handling] B --> F[Scroll Direction] B --> G[Page Transition] B --> H[Scroll Physics] C --> I[Page Index Control] C --> J[Animation Control] C --> K[Viewport Fraction] D --> L[Page Building] D --> M[Lazy Loading] D --> N[Page Caching] E --> O[Touch Gestures] E --> P[Swipe Detection] E --> Q[Gesture Conflicts] F --> R[Horizontal Scroll] F --> S[Vertical Scroll] G --> T[Page Animation] G --> U[Transition Effects] G --> V[Custom Transitions] H --> W[ClampingScrollPhysics] H --> X[BouncingScrollPhysics] H --> Y[Custom Physics]

📊 PageView 特性对比

特性 PageView PageView.builder PageView.custom
性能 ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
内存占用 ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
灵活性 ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
使用复杂度 ⭐⭐⭐ ⭐⭐⭐⭐
适用场景 固定页面 动态页面 自定义需求

基础 PageView

1. 简单的 PageView

dart 复制代码
import 'package:flutter/material.dart';

class BasicPageViewExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('基础 PageView')),
      body: PageView(
        children: [
          Container(
            color: Colors.red[100],
            child: Center(
              child: Text(
                '第一页',
                style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              ),
            ),
          ),
          Container(
            color: Colors.green[100],
            child: Center(
              child: Text(
                '第二页',
                style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              ),
            ),
          ),
          Container(
            color: Colors.blue[100],
            child: Center(
              child: Text(
                '第三页',
                style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

2. 使用 PageView.builder

dart 复制代码
class PageViewBuilderExample extends StatelessWidget {
  final List<Color> colors = [
    Colors.red,
    Colors.green,
    Colors.blue,
    Colors.orange,
    Colors.purple,
    Colors.teal,
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('PageView.builder')),
      body: PageView.builder(
        itemCount: colors.length,
        itemBuilder: (context, index) {
          return Container(
            color: colors[index].withOpacity(0.3),
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Icon(
                    Icons.pages,
                    size: 64,
                    color: colors[index],
                  ),
                  SizedBox(height: 16),
                  Text(
                    '页面 ${index + 1}',
                    style: TextStyle(
                      fontSize: 24,
                      fontWeight: FontWeight.bold,
                      color: colors[index],
                    ),
                  ),
                  SizedBox(height: 8),
                  Text(
                    '这是第 ${index + 1} 个页面',
                    style: TextStyle(
                      fontSize: 16,
                      color: colors[index].withOpacity(0.8),
                    ),
                  ),
                ],
              ),
            ),
          );
        },
      ),
    );
  }
}

带控制器的 PageView

1. 手动控制页面切换

dart 复制代码
class ControlledPageView extends StatefulWidget {
  @override
  _ControlledPageViewState createState() => _ControlledPageViewState();
}

class _ControlledPageViewState extends State<ControlledPageView> {
  late PageController _pageController;
  int _currentPage = 0;

  final List<PageData> pages = [
    PageData('欢迎', '欢迎使用我们的应用', Icons.waving_hand, Colors.blue),
    PageData('功能', '探索强大的功能特性', Icons.star, Colors.green),
    PageData('开始', '立即开始您的旅程', Icons.rocket_launch, Colors.orange),
  ];

  @override
  void initState() {
    super.initState();
    _pageController = PageController(initialPage: 0);
  }

  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('控制器 PageView')),
      body: Column(
        children: [
          // 页面指示器
          Container(
            padding: EdgeInsets.all(16),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: List.generate(pages.length, (index) {
                return Container(
                  margin: EdgeInsets.symmetric(horizontal: 4),
                  width: _currentPage == index ? 12 : 8,
                  height: 8,
                  decoration: BoxDecoration(
                    color: _currentPage == index
                        ? Colors.blue
                        : Colors.grey[300],
                    borderRadius: BorderRadius.circular(4),
                  ),
                );
              }),
            ),
          ),
          // PageView
          Expanded(
            child: PageView.builder(
              controller: _pageController,
              itemCount: pages.length,
              onPageChanged: (index) {
                setState(() {
                  _currentPage = index;
                });
              },
              itemBuilder: (context, index) {
                return _buildPage(pages[index]);
              },
            ),
          ),
          // 控制按钮
          Container(
            padding: EdgeInsets.all(16),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                ElevatedButton(
                  onPressed: _currentPage > 0 ? _previousPage : null,
                  child: Text('上一页'),
                ),
                Text('${_currentPage + 1} / ${pages.length}'),
                ElevatedButton(
                  onPressed: _currentPage < pages.length - 1 ? _nextPage : null,
                  child: Text('下一页'),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildPage(PageData pageData) {
    return Container(
      padding: EdgeInsets.all(32),
      color: pageData.color.withOpacity(0.1),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(
            pageData.icon,
            size: 80,
            color: pageData.color,
          ),
          SizedBox(height: 32),
          Text(
            pageData.title,
            style: TextStyle(
              fontSize: 28,
              fontWeight: FontWeight.bold,
              color: pageData.color,
            ),
          ),
          SizedBox(height: 16),
          Text(
            pageData.description,
            style: TextStyle(
              fontSize: 16,
              color: Colors.grey[600],
            ),
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }

  void _nextPage() {
    _pageController.nextPage(
      duration: Duration(milliseconds: 300),
      curve: Curves.easeInOut,
    );
  }

  void _previousPage() {
    _pageController.previousPage(
      duration: Duration(milliseconds: 300),
      curve: Curves.easeInOut,
    );
  }
}

class PageData {
  final String title;
  final String description;
  final IconData icon;
  final Color color;

  PageData(this.title, this.description, this.icon, this.color);
}

2. 自动轮播 PageView

dart 复制代码
class AutoPlayPageView extends StatefulWidget {
  @override
  _AutoPlayPageViewState createState() => _AutoPlayPageViewState();
}

class _AutoPlayPageViewState extends State<AutoPlayPageView> {
  late PageController _pageController;
  late Timer _timer;
  int _currentPage = 0;

  final List<BannerData> banners = [
    BannerData('轮播图1', '这是第一张轮播图', 'https://via.placeholder.com/400x200/FF5722/FFFFFF?text=Banner+1'),
    BannerData('轮播图2', '这是第二张轮播图', 'https://via.placeholder.com/400x200/4CAF50/FFFFFF?text=Banner+2'),
    BannerData('轮播图3', '这是第三张轮播图', 'https://via.placeholder.com/400x200/2196F3/FFFFFF?text=Banner+3'),
    BannerData('轮播图4', '这是第四张轮播图', 'https://via.placeholder.com/400x200/9C27B0/FFFFFF?text=Banner+4'),
  ];

  @override
  void initState() {
    super.initState();
    _pageController = PageController();
    _startAutoPlay();
  }

  @override
  void dispose() {
    _timer.cancel();
    _pageController.dispose();
    super.dispose();
  }

  void _startAutoPlay() {
    _timer = Timer.periodic(Duration(seconds: 3), (timer) {
      if (_currentPage < banners.length - 1) {
        _currentPage++;
      } else {
        _currentPage = 0;
      }

      _pageController.animateToPage(
        _currentPage,
        duration: Duration(milliseconds: 300),
        curve: Curves.easeInOut,
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('自动轮播 PageView')),
      body: Column(
        children: [
          // 轮播图
          Container(
            height: 200,
            child: PageView.builder(
              controller: _pageController,
              itemCount: banners.length,
              onPageChanged: (index) {
                setState(() {
                  _currentPage = index;
                });
              },
              itemBuilder: (context, index) {
                return _buildBanner(banners[index]);
              },
            ),
          ),
          // 指示器
          Container(
            padding: EdgeInsets.symmetric(vertical: 16),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: List.generate(banners.length, (index) {
                return GestureDetector(
                  onTap: () {
                    _pageController.animateToPage(
                      index,
                      duration: Duration(milliseconds: 300),
                      curve: Curves.easeInOut,
                    );
                  },
                  child: Container(
                    margin: EdgeInsets.symmetric(horizontal: 4),
                    width: _currentPage == index ? 24 : 8,
                    height: 8,
                    decoration: BoxDecoration(
                      color: _currentPage == index
                          ? Colors.blue
                          : Colors.grey[300],
                      borderRadius: BorderRadius.circular(4),
                    ),
                  ),
                );
              }),
            ),
          ),
          // 控制按钮
          Padding(
            padding: EdgeInsets.all(16),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(
                  onPressed: () {
                    _timer.cancel();
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('自动播放已停止')),
                    );
                  },
                  child: Text('停止自动播放'),
                ),
                ElevatedButton(
                  onPressed: () {
                    _timer.cancel();
                    _startAutoPlay();
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('自动播放已开始')),
                    );
                  },
                  child: Text('开始自动播放'),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildBanner(BannerData banner) {
    return Container(
      margin: EdgeInsets.symmetric(horizontal: 8),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(8),
        boxShadow: [
          BoxShadow(
            color: Colors.black26,
            blurRadius: 4,
            offset: Offset(0, 2),
          ),
        ],
      ),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(8),
        child: Stack(
          fit: StackFit.expand,
          children: [
            // 背景图片(这里用颜色代替)
            Container(
              color: Colors.primaries[banners.indexOf(banner) % Colors.primaries.length],
            ),
            // 文字覆盖层
            Container(
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  colors: [
                    Colors.transparent,
                    Colors.black54,
                  ],
                ),
              ),
              child: Padding(
                padding: EdgeInsets.all(16),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.end,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      banner.title,
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    SizedBox(height: 4),
                    Text(
                      banner.description,
                      style: TextStyle(
                        color: Colors.white70,
                        fontSize: 14,
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class BannerData {
  final String title;
  final String description;
  final String imageUrl;

  BannerData(this.title, this.description, this.imageUrl);
}

垂直 PageView

1. 垂直滑动页面

dart 复制代码
class VerticalPageView extends StatefulWidget {
  @override
  _VerticalPageViewState createState() => _VerticalPageViewState();
}

class _VerticalPageViewState extends State<VerticalPageView> {
  int _currentPage = 0;

  final List<StoryData> stories = [
    StoryData('故事1', '这是一个关于勇气的故事...', Icons.favorite, Colors.red),
    StoryData('故事2', '这是一个关于友谊的故事...', Icons.people, Colors.blue),
    StoryData('故事3', '这是一个关于梦想的故事...', Icons.star, Colors.orange),
    StoryData('故事4', '这是一个关于成长的故事...', Icons.trending_up, Colors.green),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('垂直 PageView')),
      body: Row(
        children: [
          // 侧边指示器
          Container(
            width: 60,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: List.generate(stories.length, (index) {
                return GestureDetector(
                  onTap: () {
                    // 这里可以添加跳转到指定页面的逻辑
                  },
                  child: Container(
                    margin: EdgeInsets.symmetric(vertical: 8),
                    width: 40,
                    height: 40,
                    decoration: BoxDecoration(
                      color: _currentPage == index
                          ? stories[index].color
                          : Colors.grey[300],
                      shape: BoxShape.circle,
                    ),
                    child: Icon(
                      stories[index].icon,
                      color: _currentPage == index
                          ? Colors.white
                          : Colors.grey[600],
                      size: 20,
                    ),
                  ),
                );
              }),
            ),
          ),
          // 垂直 PageView
          Expanded(
            child: PageView.builder(
              scrollDirection: Axis.vertical,
              itemCount: stories.length,
              onPageChanged: (index) {
                setState(() {
                  _currentPage = index;
                });
              },
              itemBuilder: (context, index) {
                return _buildStoryPage(stories[index]);
              },
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildStoryPage(StoryData story) {
    return Container(
      padding: EdgeInsets.all(24),
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
          colors: [
            story.color.withOpacity(0.1),
            story.color.withOpacity(0.3),
          ],
        ),
      ),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(
            story.icon,
            size: 80,
            color: story.color,
          ),
          SizedBox(height: 32),
          Text(
            story.title,
            style: TextStyle(
              fontSize: 28,
              fontWeight: FontWeight.bold,
              color: story.color,
            ),
          ),
          SizedBox(height: 16),
          Text(
            story.content,
            style: TextStyle(
              fontSize: 16,
              color: Colors.grey[700],
              height: 1.5,
            ),
            textAlign: TextAlign.center,
          ),
          SizedBox(height: 32),
          Text(
            '向上滑动查看下一个故事',
            style: TextStyle(
              fontSize: 12,
              color: Colors.grey[500],
            ),
          ),
        ],
      ),
    );
  }
}

class StoryData {
  final String title;
  final String content;
  final IconData icon;
  final Color color;

  StoryData(this.title, this.content, this.icon, this.color);
}

高级 PageView 功能

1. 自定义页面切换效果

dart 复制代码
class CustomTransitionPageView extends StatefulWidget {
  @override
  _CustomTransitionPageViewState createState() => _CustomTransitionPageViewState();
}

class _CustomTransitionPageViewState extends State<CustomTransitionPageView> {
  late PageController _pageController;
  double _currentPageValue = 0.0;

  final List<Color> colors = [
    Colors.red,
    Colors.green,
    Colors.blue,
    Colors.orange,
    Colors.purple,
  ];

  @override
  void initState() {
    super.initState();
    _pageController = PageController();
    _pageController.addListener(() {
      setState(() {
        _currentPageValue = _pageController.page ?? 0.0;
      });
    });
  }

  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('自定义切换效果')),
      body: PageView.builder(
        controller: _pageController,
        itemCount: colors.length,
        itemBuilder: (context, index) {
          return _buildTransformPage(index);
        },
      ),
    );
  }

  Widget _buildTransformPage(int index) {
    double value = 1.0;
    if (_pageController.position.haveDimensions) {
      value = (_currentPageValue - index).abs();
      value = (1 - (value * 0.3)).clamp(0.0, 1.0);
    }

    return Transform.scale(
      scale: value,
      child: Container(
        margin: EdgeInsets.all(16),
        decoration: BoxDecoration(
          color: colors[index],
          borderRadius: BorderRadius.circular(16),
          boxShadow: [
            BoxShadow(
              color: colors[index].withOpacity(0.3),
              blurRadius: 10,
              offset: Offset(0, 5),
            ),
          ],
        ),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Icon(
                Icons.pages,
                size: 64,
                color: Colors.white,
              ),
              SizedBox(height: 16),
              Text(
                '页面 ${index + 1}',
                style: TextStyle(
                  fontSize: 24,
                  fontWeight: FontWeight.bold,
                  color: Colors.white,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

2. 无限循环 PageView

dart 复制代码
class InfinitePageView extends StatefulWidget {
  @override
  _InfinitePageViewState createState() => _InfinitePageViewState();
}

class _InfinitePageViewState extends State<InfinitePageView> {
  late PageController _pageController;

  final List<ImageData> images = [
    ImageData('图片1', Icons.image, Colors.red),
    ImageData('图片2', Icons.photo, Colors.green),
    ImageData('图片3', Icons.camera_alt, Colors.blue),
    ImageData('图片4', Icons.photo_camera, Colors.orange),
  ];

  @override
  void initState() {
    super.initState();
    // 从中间位置开始,实现无限循环的效果
    _pageController = PageController(initialPage: images.length * 1000);
  }

  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('无限循环 PageView')),
      body: PageView.builder(
        controller: _pageController,
        itemBuilder: (context, index) {
          // 使用模运算实现循环
          final realIndex = index % images.length;
          return _buildImagePage(images[realIndex], realIndex);
        },
      ),
    );
  }

  Widget _buildImagePage(ImageData imageData, int index) {
    return Container(
      margin: EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: imageData.color.withOpacity(0.1),
        borderRadius: BorderRadius.circular(16),
        border: Border.all(color: imageData.color, width: 2),
      ),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(
            imageData.icon,
            size: 80,
            color: imageData.color,
          ),
          SizedBox(height: 16),
          Text(
            imageData.title,
            style: TextStyle(
              fontSize: 24,
              fontWeight: FontWeight.bold,
              color: imageData.color,
            ),
          ),
          SizedBox(height: 8),
          Text(
            '索引: $index',
            style: TextStyle(
              fontSize: 16,
              color: Colors.grey[600],
            ),
          ),
          SizedBox(height: 16),
          Text(
            '可以无限向左右滑动',
            style: TextStyle(
              fontSize: 14,
              color: Colors.grey[500],
            ),
          ),
        ],
      ),
    );
  }
}

class ImageData {
  final String title;
  final IconData icon;
  final Color color;

  ImageData(this.title, this.icon, this.color);
}

实际应用案例

1. 应用引导页

dart 复制代码
class OnboardingPageView extends StatefulWidget {
  @override
  _OnboardingPageViewState createState() => _OnboardingPageViewState();
}

class _OnboardingPageViewState extends State<OnboardingPageView> {
  late PageController _pageController;
  int _currentPage = 0;

  final List<OnboardingData> onboardingPages = [
    OnboardingData(
      '欢迎使用',
      '感谢您选择我们的应用,让我们开始这段美妙的旅程',
      Icons.waving_hand,
      Colors.blue,
    ),
    OnboardingData(
      '强大功能',
      '我们为您提供了丰富的功能,让您的体验更加完美',
      Icons.star,
      Colors.green,
    ),
    OnboardingData(
      '简单易用',
      '直观的界面设计,让您轻松上手,享受流畅的操作体验',
      Icons.touch_app,
      Colors.orange,
    ),
    OnboardingData(
      '开始使用',
      '一切准备就绪,现在就开始探索我们的应用吧!',
      Icons.rocket_launch,
      Colors.purple,
    ),
  ];

  @override
  void initState() {
    super.initState();
    _pageController = PageController();
  }

  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            // 跳过按钮
            Align(
              alignment: Alignment.topRight,
              child: Padding(
                padding: EdgeInsets.all(16),
                child: TextButton(
                  onPressed: _skipOnboarding,
                  child: Text('跳过'),
                ),
              ),
            ),
            // PageView
            Expanded(
              child: PageView.builder(
                controller: _pageController,
                itemCount: onboardingPages.length,
                onPageChanged: (index) {
                  setState(() {
                    _currentPage = index;
                  });
                },
                itemBuilder: (context, index) {
                  return _buildOnboardingPage(onboardingPages[index]);
                },
              ),
            ),
            // 指示器和按钮
            Padding(
              padding: EdgeInsets.all(24),
              child: Column(
                children: [
                  // 页面指示器
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: List.generate(onboardingPages.length, (index) {
                      return AnimatedContainer(
                        duration: Duration(milliseconds: 300),
                        margin: EdgeInsets.symmetric(horizontal: 4),
                        width: _currentPage == index ? 24 : 8,
                        height: 8,
                        decoration: BoxDecoration(
                          color: _currentPage == index
                              ? onboardingPages[index].color
                              : Colors.grey[300],
                          borderRadius: BorderRadius.circular(4),
                        ),
                      );
                    }),
                  ),
                  SizedBox(height: 24),
                  // 下一步/完成按钮
                  SizedBox(
                    width: double.infinity,
                    height: 50,
                    child: ElevatedButton(
                      onPressed: _nextPage,
                      style: ElevatedButton.styleFrom(
                        backgroundColor: onboardingPages[_currentPage].color,
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(25),
                        ),
                      ),
                      child: Text(
                        _currentPage == onboardingPages.length - 1
                            ? '开始使用'
                            : '下一步',
                        style: TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.bold,
                          color: Colors.white,
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildOnboardingPage(OnboardingData data) {
    return Padding(
      padding: EdgeInsets.all(32),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(
            data.icon,
            size: 120,
            color: data.color,
          ),
          SizedBox(height: 48),
          Text(
            data.title,
            style: TextStyle(
              fontSize: 28,
              fontWeight: FontWeight.bold,
              color: data.color,
            ),
            textAlign: TextAlign.center,
          ),
          SizedBox(height: 24),
          Text(
            data.description,
            style: TextStyle(
              fontSize: 16,
              color: Colors.grey[600],
              height: 1.5,
            ),
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }

  void _nextPage() {
    if (_currentPage < onboardingPages.length - 1) {
      _pageController.nextPage(
        duration: Duration(milliseconds: 300),
        curve: Curves.easeInOut,
      );
    } else {
      _completeOnboarding();
    }
  }

  void _skipOnboarding() {
    _completeOnboarding();
  }

  void _completeOnboarding() {
    // 这里可以导航到主页面或保存引导完成状态
    Navigator.of(context).pushReplacement(
      MaterialPageRoute(builder: (context) => MainApp()),
    );
  }
}

class OnboardingData {
  final String title;
  final String description;
  final IconData icon;
  final Color color;

  OnboardingData(this.title, this.description, this.icon, this.color);
}

// 主应用页面(示例)
class MainApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('主应用')),
      body: Center(
        child: Text(
          '欢迎来到主应用!',
          style: TextStyle(fontSize: 24),
        ),
      ),
    );
  }
}

2. 图片浏览器

dart 复制代码
class ImageGalleryPageView extends StatefulWidget {
  final List<String> imageUrls;
  final int initialIndex;

  ImageGalleryPageView({
    required this.imageUrls,
    this.initialIndex = 0,
  });

  @override
  _ImageGalleryPageViewState createState() => _ImageGalleryPageViewState();
}

class _ImageGalleryPageViewState extends State<ImageGalleryPageView> {
  late PageController _pageController;
  late int _currentIndex;

  @override
  void initState() {
    super.initState();
    _currentIndex = widget.initialIndex;
    _pageController = PageController(initialPage: widget.initialIndex);
  }

  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      appBar: AppBar(
        backgroundColor: Colors.black,
        title: Text(
          '${_currentIndex + 1} / ${widget.imageUrls.length}',
          style: TextStyle(color: Colors.white),
        ),
        iconTheme: IconThemeData(color: Colors.white),
        actions: [
          IconButton(
            icon: Icon(Icons.share),
            onPressed: _shareImage,
          ),
          IconButton(
            icon: Icon(Icons.download),
            onPressed: _downloadImage,
          ),
        ],
      ),
      body: PageView.builder(
        controller: _pageController,
        itemCount: widget.imageUrls.length,
        onPageChanged: (index) {
          setState(() {
            _currentIndex = index;
          });
        },
        itemBuilder: (context, index) {
          return _buildImagePage(widget.imageUrls[index], index);
        },
      ),
      bottomNavigationBar: Container(
        color: Colors.black,
        padding: EdgeInsets.all(16),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            IconButton(
              icon: Icon(Icons.zoom_in, color: Colors.white),
              onPressed: _zoomIn,
            ),
            IconButton(
              icon: Icon(Icons.zoom_out, color: Colors.white),
              onPressed: _zoomOut,
            ),
            IconButton(
              icon: Icon(Icons.rotate_right, color: Colors.white),
              onPressed: _rotateImage,
            ),
            IconButton(
              icon: Icon(Icons.info, color: Colors.white),
              onPressed: _showImageInfo,
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildImagePage(String imageUrl, int index) {
    return InteractiveViewer(
      panEnabled: true,
      boundaryMargin: EdgeInsets.all(20),
      minScale: 0.5,
      maxScale: 4.0,
      child: Center(
        child: Container(
          decoration: BoxDecoration(
            color: Colors.grey[300],
            borderRadius: BorderRadius.circular(8),
          ),
          child: Icon(
            Icons.image,
            size: 200,
            color: Colors.grey[600],
          ),
          // 在实际应用中,这里应该是 Image.network(imageUrl)
        ),
      ),
    );
  }

  void _shareImage() {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('分享图片 ${_currentIndex + 1}')),
    );
  }

  void _downloadImage() {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('下载图片 ${_currentIndex + 1}')),
    );
  }

  void _zoomIn() {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('放大图片')),
    );
  }

  void _zoomOut() {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('缩小图片')),
    );
  }

  void _rotateImage() {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('旋转图片')),
    );
  }

  void _showImageInfo() {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('图片信息'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('图片编号: ${_currentIndex + 1}'),
            Text('总数量: ${widget.imageUrls.length}'),
            Text('URL: ${widget.imageUrls[_currentIndex]}'),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: Text('确定'),
          ),
        ],
      ),
    );
  }
}

最佳实践

1. 性能优化

  • 懒加载 : 使用 PageView.builder 实现按需构建
  • 内存管理: 及时释放 PageController
  • 图片优化: 对于图片轮播,使用适当的缓存策略

2. 用户体验

  • 平滑动画: 使用合适的动画曲线和持续时间
  • 视觉反馈: 提供清晰的页面指示器
  • 手势支持: 支持滑动、点击等多种交互方式

3. 可访问性

  • 语义化: 为页面内容提供清晰的语义描述
  • 键盘导航: 支持键盘切换页面
  • 屏幕阅读器: 确保内容可被屏幕阅读器正确识别

总结

PageView 是 Flutter 中实现页面滑动切换的核心组件,通过合理的配置和自定义,可以创建出丰富多样的页面切换效果。在实际应用中,要注意性能优化和用户体验的平衡,特别是在处理大量页面或复杂内容时。

相关推荐
Lanren的编程日记1 小时前
Flutter鸿蒙应用开发:生物识别(指纹/面容)功能集成实战
flutter·华为·harmonyos
Lanren的编程日记5 小时前
Flutter鸿蒙应用开发:基础UI组件库设计与实现实战
flutter·ui·harmonyos
西西学代码5 小时前
Flutter---波形动画
flutter
于慨8 小时前
flutter基础组件用法
开发语言·javascript·flutter
恋猫de小郭10 小时前
Android CLI ,谷歌为 Android 开发者专研的 AI Agent,提速三倍
android·前端·flutter
火柴就是我11 小时前
flutter pushAndRemoveUntil 的一次小疑惑
flutter
于慨12 小时前
flutter doctor问题解决
flutter
唔6612 小时前
flutter 图片加载类 图片的安全使用
安全·flutter
Nathan2024061613 小时前
Flutter - InheritedWidget
flutter·dart
恋猫de小郭13 小时前
JetBrains Amper 0.10 ,期待它未来替代 Gradle
android·前端·flutter