IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Flutter 自定义ScrollPhysics实现PageView禁止左滑或右滑 -> 正文阅读

[移动开发]Flutter 自定义ScrollPhysics实现PageView禁止左滑或右滑

1 PageView禁止左滑或右滑效果图

在这里插入图片描述


2 PageView

PageView可实现Widget的整页滑动切换,可用于轮播图、App左右切换TAB页面、引导页切换页面等场景。

2.1 PageView示例

class PageViewPage extends StatefulWidget {
  const PageViewPage({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _PageViewPageState();
}

class _PageViewPageState extends State<PageViewPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PageView(
        children: List.generate(3, _buildChildPage),
      ),
    );
  }

  Widget _buildChildPage(int index) {
    return Container(
      color: Colors.primaries[index * 2],
      child: Center(
        child: Text(
          'Page  $index',
          style: const TextStyle(color: Colors.white, fontSize: 24),
        ),
      ),
    );
  }
}

画面效果
在这里插入图片描述


2.2 ScrollPhysics

ScrollPhysics 用于确定可滑动的Widget的滑动物理特效,常用几种的ScrollPhysics如下:

  • NeverScrollableScrollPhysics
    不允许左右滑动。
  • BouncingScrollPhysics
    iOS风格的滑动效果,有物理弹性,和上图的滑动效果一致。
  • ClampingScrollPhysics
    Android风格的滑动效果,无弹性效果,滑到底部后不允许继续滑。

PageView的physics属性的默认值是PageScrollPhysics,若不自己设置,最终的滑动效果会根据系统的特性来展示。

3 自定义ScrollPhysics实现PageView禁止左滑或右滑

需求是禁止左滑或右滑,和ClampingScrollPhysics的滑到底就禁止滑动有共通之处,所以自定义时可参考ClampingScrollPhysics

3.1 ClampingScrollPhysics源码

查看源码ClampingScrollPhysics源码

class ClampingScrollPhysics extends ScrollPhysics {
  /// Creates scroll physics that prevent the scroll offset from exceeding the
  /// bounds of the content.
  const ClampingScrollPhysics({ ScrollPhysics? parent }) : super(parent: parent);

  @override
  ClampingScrollPhysics applyTo(ScrollPhysics? ancestor) {
    return ClampingScrollPhysics(parent: buildParent(ancestor));
  }

  @override
  double applyBoundaryConditions(ScrollMetrics position, double value) {
    print(
        'value:$value  maxScrollExtent:${position.maxScrollExtent}  minScrollExtent:${position.minScrollExtent}');
    print('position.pixels:${position.pixels}');
    print('value - position.pixels:${value - position.pixels}');

    if (value < position.pixels && position.pixels <= position.minScrollExtent) // underscroll
      return value - position.pixels;
    if (position.maxScrollExtent <= position.pixels && position.pixels < value) // overscroll
      return value - position.pixels;
    if (value < position.minScrollExtent && position.minScrollExtent < position.pixels) // hit top edge
      return value - position.minScrollExtent;
    if (position.pixels < position.maxScrollExtent && position.maxScrollExtent < value) // hit bottom edge
      return value - position.maxScrollExtent;
    return 0.0;
  }

  @override
  Simulation? createBallisticSimulation(ScrollMetrics position, double velocity) {
    final Tolerance tolerance = this.tolerance;
    if (position.outOfRange) {
      double? end;
      if (position.pixels > position.maxScrollExtent)
        end = position.maxScrollExtent;
      if (position.pixels < position.minScrollExtent)
        end = position.minScrollExtent;
      assert(end != null);
      return ScrollSpringSimulation(
        spring,
        position.pixels,
        end!,
        math.min(0.0, velocity),
        tolerance: tolerance,
      );
    }
    if (velocity.abs() < tolerance.velocity)
      return null;
    if (velocity > 0.0 && position.pixels >= position.maxScrollExtent)
      return null;
    if (velocity < 0.0 && position.pixels <= position.minScrollExtent)
      return null;
    return ClampingScrollSimulation(
      position: position.pixels,
      velocity: velocity,
      tolerance: tolerance,
    );
  }
}

发现只重写了3个方法:

  • applyTo 自定义ScrollPhysics必须重写的方法
  • applyBoundaryConditions 通过返回值来确定是否已到达边界,即确定是否可滑动的方法
  • createBallisticSimulation 确定滑动的效果

判断能否滑动的核心在于applyBoundaryConditions方法,在该方法中添加日志打印。

处于第一页,往右滑动无法滑动的日志。
在这里插入图片描述

处于最后一页,往左滑无法滑动的日志
在这里插入图片描述

现象

  • 往左滑value会变大,往右滑value会变小
  • 无法左滑时,position.pixels 等于 minScrollExtent
  • 无法右滑时,position.pixels 等于 maxScrollExtent
  • value 是本次滑动将要滑到的位置
  • 假定position.pixels所处的位置不允许滑动(即已经是边界),value - position.pixels就是滑动将要超出边界的值

结论
在applyBoundaryConditions中只需返回(value - position.pixels)即可禁止滑动,返回0即可以滑动。

3.2 自定义ScrollPhysics

ScrollPhysics 由@immutable标记,是不可变的,所以需要新建一个Controller来存储或改变需要的变量。

新建 CustomScrollPhysicsController

class CustomScrollPhysicsController {
  // 禁止左滑或右滑
  late bool banSwipeRight;
  late bool banSwipeLeft;

  // 记录 CustomScrollPhysics 滑动的值
  double? _lastSwipePosition;

  CustomScrollPhysicsController({
    this.banSwipeRight = false,
    this.banSwipeLeft = false,
  });
}

因为需求与ClampingScrollPhysics很相似,所以直接继承于ClampingScrollPhysics

class CustomScrollPhysics extends ClampingScrollPhysics {
  final CustomScrollPhysicsController controller;

  const CustomScrollPhysics({
    super.parent,
    required this.controller,
  });

  /// 必须实现的方法
  @override
  CustomScrollPhysics applyTo(ScrollPhysics? ancestor) {
    return CustomScrollPhysics(
      parent: buildParent(ancestor),
      controller: controller,
    );
  }

  /// 返回值,确定要限制滑动的距离
  @override
  double applyBoundaryConditions(ScrollMetrics position, double value) {
    // 处理 禁止左滑或右滑
    final lastSwipePosition = controller._lastSwipePosition;
    if (lastSwipePosition != null) {
      // 手势往左滑 value值会越来越大,往右滑 value会越来越小
      // 此时将要往左滑   但禁止往左滑
      if (value > lastSwipePosition && controller.banSwipeLeft) {
        // 返回要限制的滑动距离 抵消滑动
        return value - position.pixels;
      }
      // 此时将要往右滑 但禁止往右滑
      if (value < lastSwipePosition && controller.banSwipeRight) {
        // 返回要限制的滑动距离 抵消滑动
        return value - position.pixels;
      }
    }
    controller._lastSwipePosition = value;

    return super.applyBoundaryConditions(position, value);
  }
}

使用方式

final _physicsController = CustomScrollPhysicsController();

// 构建PageView
 PageView(
   physics: CustomScrollPhysics(controller: _physicsController),
   children: List.generate(3, _buildChildPage),
 ),

// 设置是否禁用滑动
_physicsController.banSwipeLeft = true;
_physicsController.banSwipeRight = true;

最终效果

在这里插入图片描述

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-07-03 10:57:45  更:2022-07-03 10:58:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/3 22:31:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码