我想用水平分页卷轴呈现卡片,并且每次看到上一张和下一张卡片时都能看到它的边框.Ffltter Pageview小部件几乎产生了我想要的结果,但是它没有以我想要的方式显示页面对齐,这是我的代码

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'PageView Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'PageView Alignment'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: PageView.builder(
        itemCount: 5,
        itemBuilder: (context, i) => Container(
              color: Colors.blue,
              margin: const EdgeInsets.only(right: 10),
              child: Center(child: Text("Page $i")),
            ),
        controller: PageController(viewportFraction: .7),
      ),
    );
  }
}

这是上述代码产生的结果 enter image description here

我希望页面视图与屏幕左侧对齐,或者至少与第一页对齐,即删除Page 0页左侧的空白.我有没有缺少页面浏览参数?或者是否存在产生我想要的结果的其他成分?

推荐答案

在对自己的需求进行深入分析并判断PageView小部件的源代码后,我意识到我需要一个逐项工作的滚动小部件,但同时我需要每个项目的空间都与普通滚动条相同,因此我需要更改普通滚动条的ScrollPhysics.在found this post中,它在某种程度上描述了Flutter 中的卷轴物理,并接近我的需求,不同之处在于我需要在当前可见小部件的两个侧面添加空间,而不仅仅是右侧.

因此,我在帖子中 Select 了CustomScrollPhysics,并以这种方式对其进行了修改(帖子代码中更改的部分用H <---->注释表示:

class CustomScrollPhysics extends ScrollPhysics {
  final double itemDimension;

  const CustomScrollPhysics(
      {required this.itemDimension, ScrollPhysics? parent})
      : super(parent: parent);

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

  double _getPage(ScrollMetrics position, double portion) {
    // <--
    return (position.pixels + portion) / itemDimension;
    // -->
  }

  double _getPixels(double page, double portion) {
    // <--
    return (page * itemDimension) - portion;
    // -->
  }

  double _getTargetPixels(
    ScrollMetrics position,
    Tolerance tolerance,
    double velocity,
    double portion,
  ) {
    // <--
    double page = _getPage(position, portion);
    // -->
    if (velocity < -tolerance.velocity) {
      page -= 0.5;
    } else if (velocity > tolerance.velocity) {
      page += 0.5;
    }
    // <--
    return _getPixels(page.roundToDouble(), portion);
    // -->
  }

  @override
  Simulation? createBallisticSimulation(
      ScrollMetrics position, double velocity) {
    // If we're out of range and not headed back in range, defer to the parent
    // ballistics, which should put us back in range at a page boundary.
    if ((velocity <= 0.0 && position.pixels <= position.minScrollExtent) ||
        (velocity >= 0.0 && position.pixels >= position.maxScrollExtent)) {
      return super.createBallisticSimulation(position, velocity);
    }

    final Tolerance tolerance = this.tolerance;
    // <--
    final portion = (position.extentInside - itemDimension) / 2;
    final double target =
        _getTargetPixels(position, tolerance, velocity, portion);
    // -->
    if (target != position.pixels) {
      return ScrollSpringSimulation(spring, position.pixels, target, velocity,
          tolerance: tolerance);
    }
    return null;
  }

  @override
  bool get allowImplicitScrolling => false;
}

总而言之,我所做的是提取当前可见小部件留下的额外空间的一半(即(position.extentInside - itemDimension) / 2),并将其添加到基于滚动位置的页面计算中,允许小部件小于可见滚动大小,但将整个范围视为单个页面,并将其减go 基于页面的滚动像素计算,从而防止"页面"被放置在其侧面的小部件的半可见部分之前或之后.

另一个变化是,itemDimension不是滚动范围除以元素数量,我需要这个值作为滚动方向上每个小部件的大小.

这就是我的结局:

final result

当然,此实现有一些限制:

  • 滚动方向上每个元素的大小必须是固定的,如果单个元素的大小不同,则整个滚动的行为会不规律
  • 如果存在填充,那么大小必须包括填充,否则将产生与使用不同大小的小部件相同的效果

我没有把重点放在解决这个限制和拥有一个更完整的小部件上,因为在我需要这个小部件的情况下,这个限制是可以保证的.下面是上述示例的完整代码.

https://gist.github.com/rolurq/5db4c0cb7db66cf8f5a59396faeec7fa

Dart相关问答推荐

为什么使用三元条件运算符会产生return_of_invalid_type错误?

如何在 Dart 2.17+ 中处理future 的枚举值

当未指定返回类型时,dart 显示另一个函数内部的确切返回类型,但对于顶层函数显示为动态

在启用 null 安全性的情况下,如何在 Iterable.firstWhere 中从 orElse 返回 null?

Flutter - 自定义按钮点击区域

在dart polymer重复模板中获取索引

Flutter:[cloud_firestore/unknown] NoSuchMethodError:null 上的无效成员:'includeMetadataChanges'(Flutter Web)

如何防止键盘在Flutter中按提交键时失效?

将Dart嵌入到应用程序中

如何提取dart/Flutter视频元数据

如何实现从左侧滑动的侧边菜单?

在字符串中查找字母 (charAt)

可选参数的默认值

如何在 Dart 中创建 StreamTransformer?

Dart:如何在异步函数中管理并发

用默认值初始化成员的最优雅的方法

如何构建具有多个视图的复杂 Web UI 应用程序?

如何从 Dart 中的 forEach 循环返回?

Dart 中 == 和 === 有什么区别?

dart:io 中带有 json 内容类型的 Http POST 请求