【Flutter&Dart】页面切换 PageView &PageController(9 /100)

上效果:

有些不能理解官方例子里的动画为什么没有效果,有可能是我写法不对

后续如果有动画效果修复了,再更新这篇,没有动画效果,总觉得感受的丝滑效果差了很多

上代码:

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

const TAG = 'OfficePageViewDemo';

class OfficePageViewDemo extends StatelessWidget {
  const OfficePageViewDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('PageView Demo!'),
        ),
        body: PageViewDemo(),
      ),
    );
  }
}

class PageViewDemo extends StatefulWidget {
  const PageViewDemo({super.key});

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

class _PageViewDemoState extends State<PageViewDemo>
    with TickerProviderStateMixin {
  late PageController _pageViewController;
  late TabController _tabController;
  int _currentPageIndex = 0;

  @override
  void initState() {
    super.initState();
    _pageViewController = PageController();
    _tabController = TabController(length: 3, vsync: this);
  }

  @override
  void dispose() {
    super.dispose();
    _pageViewController.dispose();
    _tabController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final TextTheme textTheme = Theme.of(context).textTheme;

    return Stack(
      alignment: Alignment.bottomCenter,
      children: [
        PageView(
          controller: _pageViewController,
          onPageChanged: _handlePageViewChanged,
          children: [
            Center(
              child: Text(
                'First Page',
                style: textTheme.titleLarge,
              ),
            ),
            Center(
              child: Text(
                'Second Page',
                style: textTheme.titleLarge,
              ),
            ),
            Center(
              child: Text(
                'Third Page',
                style: textTheme.titleLarge,
              ),
            ),
          ],
        ),
        PageIndicator(
          tabController: _tabController,
          currentPageIndex: _currentPageIndex,
          onUpdateCurrentPageIndex: _updateCurrentPageIndex,
          isOnDesktopAndWeb: _isOnDesktopAndWeb,
        )
      ],
    );
  }

  void _handlePageViewChanged(int currentPageIndex) {
    Logger(TAG).info(
        '_handlePageViewChanged called! currentPageIndex=$currentPageIndex');

    if (!_isOnDesktopAndWeb) {
      return;
    }
    _tabController.index = currentPageIndex;
    setState(() {
      _currentPageIndex = currentPageIndex;
    });
  }

  void _updateCurrentPageIndex(int index) {
    Logger(TAG).info('_updateCurrentPageIndex called! index=$index');

    _tabController.index = index;
    _pageViewController.animateToPage(index,
        duration: const Duration(microseconds: 400 * 2), curve: Curves.linear);
  }

  bool get _isOnDesktopAndWeb {
    if (kIsWeb) {
      return true;
    }
    switch (defaultTargetPlatform) {
      case TargetPlatform.macOS:
      case TargetPlatform.linux:
      case TargetPlatform.windows:
        return true;
      case TargetPlatform.android:
      case TargetPlatform.iOS:
      case TargetPlatform.fuchsia:
        return false;
    }
  }
}

class PageIndicator extends StatelessWidget {
  const PageIndicator(
      {super.key,
      required this.tabController,
      required this.currentPageIndex,
      required this.onUpdateCurrentPageIndex,
      required this.isOnDesktopAndWeb});

  final int currentPageIndex;
  final TabController tabController;
  final void Function(int) onUpdateCurrentPageIndex;
  final bool isOnDesktopAndWeb;

  @override
  Widget build(BuildContext context) {
    if (!isOnDesktopAndWeb) {
      return const SizedBox();
    }
    final ColorScheme colorScheme = Theme.of(context).colorScheme;

    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          IconButton(
              splashRadius: 16.0,
              padding: EdgeInsets.zero,
              onPressed: () => {
                    if (currentPageIndex == 0)
                      {}
                    else
                      {onUpdateCurrentPageIndex(currentPageIndex - 1)}
                  },
              icon: const Icon(
                Icons.arrow_left_rounded,
                size: 32.0,
              )),
          TabPageSelector(
            controller: tabController,
            color: colorScheme.surface,
            selectedColor: colorScheme.primary,
          ),
          IconButton(
              splashRadius: 16.0,
              padding: EdgeInsets.zero,
              onPressed: () => {
                    if (currentPageIndex == 2)
                      {}
                    else
                      {onUpdateCurrentPageIndex(currentPageIndex + 1)}
                  },
              icon: const Icon(
                Icons.arrow_right_rounded,
                size: 32.0,
              )),
        ],
      ),
    );
  }
}

事实就是官方代码,不过有点细微差别

有解决动画效果的回复一下蛤!

还差一个拖动边界框改变 widget 的宽高效果;

========END

相关推荐
2501_9159214313 分钟前
常用iOS性能测试工具大全及使用指南
android·测试工具·ios·小程序·uni-app·cocoa·iphone
晨尘光15 分钟前
【Android下载gradle超时解决方法】
android
zhen_hong20 分钟前
ReactAgent原理
android·java·javascript
皮皮宋吖28 分钟前
皮皮宋渗透日记 11|文件包含漏洞全解析:LFI/RFI/ 伪协议 / 绕过 / 防御
android·安全
阿拉斯攀登33 分钟前
【无人售货柜・RK+YOLO】篇 6:安卓端落地!RK3576 + 安卓系统,YOLO RKNN 模型实时推理保姆级教程
android·人工智能·yolo·目标跟踪·瑞芯微·嵌入式驱动
for_ever_love__1 小时前
Objecgtive-C学习实例对象,类对象, 元类对象与 isa指针
c语言·学习·ios
半个俗人1 小时前
3.postman全局变量和环境变量
测试工具·postman
只能是遇见1 小时前
ERROR 1524 (HY000) Plugin ‘mysql_native_password‘ is not loaded
android·数据库·mysql
API开发1 小时前
一个MCP操作所有的数据库
数据库·api·api接口·apisql·mcp·mcpserver·openclaw
一招定胜负1 小时前
视频转写+LLM分析:课堂录音自动化处理实现
macos·ios·xcode