繁体   English   中英

使用自定义ScrollPhysics调整具有动态边界的PageView

[英]flutter PageView with dynamic boundary using custom ScrollPhysics

我正在尝试动态设置PageView边界。 这是一个简化的示例,从第10页开始,左右边界由随机数生成器(leftEnd,rightEnd)设置。

import 'package:flutter/material.dart';
import 'dart:math';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      home: new MyTabbedPage(),
    );
  }
}

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

  @override
  _MyTabbedPageState createState() => new _MyTabbedPageState();
}

class _MyTabbedPageState extends State<MyTabbedPage> with SingleTickerProviderStateMixin {
  final leftEnd = Random().nextInt(5);
  final rightEnd = 10 + Random().nextInt(5);
  CustomScrollPhysics scrollPhysics = CustomScrollPhysics();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: PageView.builder(
          controller: PageController(initialPage: 10),
          physics: scrollPhysics,
          itemBuilder: (context, index) {
            scrollPhysics.leftEnd = (index <= leftEnd);
            scrollPhysics.rightEnd = (index >= rightEnd);

            // --------- print (1) ----------
            print("is leftEnd: ${index <= leftEnd}");
            print("is rightEnd: ${index >= rightEnd}");
            print("scrollphysics.leftEnd: ${scrollPhysics.leftEnd}");
            print("scrollphysics.rightEnd: ${scrollPhysics.rightEnd}");
            return Center(
              child: Text("Item $index"),
            );
          }
        ));
  }
}

class CustomScrollPhysics extends ScrollPhysics {
  CustomScrollPhysics({ScrollPhysics parent}) : super(parent: parent);

  bool leftEnd = false;
  bool rightEnd = false;
  bool isGoingLeft = false;

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

  @override
  double applyPhysicsToUserOffset(ScrollMetrics position, double offset) {
    isGoingLeft = offset.sign < 0;
    return offset;
  }

  @override
  double applyBoundaryConditions(ScrollMetrics position, double value) {
    //print("applyBoundaryConditions");
    assert(() {
      if (value == position.pixels) {
        throw FlutterError(
            '$runtimeType.applyBoundaryConditions() was called redundantly.\n'
                'The proposed new position, $value, is exactly equal to the current position of the '
                'given ${position.runtimeType}, ${position.pixels}.\n'
                'The applyBoundaryConditions method should only be called when the value is '
                'going to actually change the pixels, otherwise it is redundant.\n'
                'The physics object in question was:\n'
                '  $this\n'
                'The position object in question was:\n'
                '  $position\n');
      }
      return true;
    }());
    if (value < position.pixels && position.pixels <= position.minScrollExtent)
      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;

    // --------- print (2) ----------
    if (leftEnd) print("leftEnd");
    if (rightEnd) print("rightEnd");
    if (isGoingLeft) print("isGoingLeft");

    if (leftEnd && !isGoingLeft) {
      return value - position.pixels;
    } else if (rightEnd && isGoingLeft) {
      return value - position.pixels;
    }
    return 0.0;
  }
}

scrollphysics.leftEnd / rightEnd在PageView.builder内部更改(基于打印结果(1)),但在CustomScrollPhysics中没有更改(无打印结果(2))。

谁能解释这是怎么回事? 这是为PageView设置动态边界的正确方法吗?

CustomScrollPhysics扩展自其的ScrollPhysics被标记为不可变的 即使您在itemBuilder中更改其布尔值,实际的布尔值也不会更改( rightEndapplyBoundaryConditions打印leftEndrightEnd applyBoundaryConditions )。 我没有正式的解释,为什么scrollPhysics.leftEnd中的itemBuilder在类本身未更改时会显示所需的已更改布尔值,但是我想这是因为您没有将这些变量设置为final be并且没有任何东西阻止您更改它们,因此scrollPhysics中的本地_MyTabbedPageState将显示这些更改,即使它们在内部未更改。 isGoingLeft只被打印是因为它在CustomScrollPhysics本身内部而不是从外部更改,如itemBuilder

作为快速解决方案,我创建了另一个类:

class Status {
  bool leftEnd = false;
  bool rightEnd = false;
  bool isGoingLeft = false;
}

更改了CustomScrollPhysics

class CustomScrollPhysics extends ScrollPhysics {
  final Status status;

  CustomScrollPhysics(this.status, {ScrollPhysics parent})
      : super(parent: parent);

  @override
  CustomScrollPhysics applyTo(ScrollPhysics ancestor) {
    return CustomScrollPhysics(this.status, parent: buildParent(ancestor));
  }

  ...

并在您的状态的构造函数调用中添加了一个Status实例:

CustomScrollPhysics scrollPhysics = CustomScrollPhysics(Status());

将所有更改应用于CustomScrollPhysics this.status 现在,它应该可以按预期工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM