简体   繁体   English

ListView PageScrollPhysics 基于子宽度/ PageView 与 viewportFraction < 1 对齐左对齐

[英]ListView PageScrollPhysics snapping based on children width / PageView with viewportFraction < 1 align left

I have a PageView/ListView with a viewportFraction of 0.8 to show a preview of the next slide.我有一个viewportFraction为 0.8 的 PageView/ListView 来显示下一张幻灯片的预览。 It looks something like this:它看起来像这样:

在此处输入图像描述

It seems like it is not possible to have the current slide aligned to the left, as shown below.似乎不可能让当前幻灯片向左对齐,如下所示。 Is that correct?那是对的吗?

在此处输入图像描述

I found this solution.我找到了这个解决方案。 Using a horizontally scrolling ListView with PageScrollPhysics() , at first looked promising however, this way the page snapping is based on the screen width (?) and not on the ListView children, so the snapping is off by quite a bit.使用带有PageScrollPhysics()的水平滚动 ListView ,起初看起来很有希望,但是这种方式页面捕捉是基于屏幕宽度(?)而不是 ListView 子级,因此捕捉相当多。

Is there a way to have the page snapping based on the size of the children?有没有办法根据孩子的大小来捕捉页面?

My answer comes a bit late but it might help others looking for the same thing.我的回答来得有点晚,但它可能会帮助其他人寻找同样的东西。 the PageScrollPhysics uses the screen width. PageScrollPhysics 使用屏幕宽度。 You need to create your own ScrollPhysics that uses your item width to paginate.您需要创建自己的 ScrollPhysics,使用您的项目宽度进行分页。 here is an example:这是一个例子:

ListView.builder(
    physics: PagingScrollPhysics(itemDimension: YOUR_ITEM_WIDTH),
    itemCount:items.length,
    scrollDirection: Axis.horizontal,
    itemBuilder: (context, index) {
        return YOUR_CHILD();
    }
)

And the new ScrollPhysics:还有新的 ScrollPhysics:

import 'package:flutter/material.dart';

class PagingScrollPhysics extends ScrollPhysics {
  final double itemDimension;

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

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

  double _getPage(ScrollMetrics position) {
    return position.pixels / itemDimension;
  }

  double _getPixels(double page) {
    return page * itemDimension;
  }

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

  @override
  Simulation? createBallisticSimulation(ScrollMetrics position, double velocity) {
    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 double target = _getTargetPixels(position, tolerance, velocity);
    if (target != position.pixels) return ScrollSpringSimulation(spring, position.pixels, target, velocity, tolerance: tolerance);
    return null;
  }

  @override
  bool get allowImplicitScrolling => false;
}

I modified the code of Alaa Eddine Cherbib's answer in order to show smoothly scrolling for all elements when it is a fixed-size list.我修改了 Alaa Eddine Cherbib 答案的代码,以便在它是固定大小的列表时显示所有元素的平滑滚动。 Now instead of passing item dimension, you should pass the item count and the view size (usually the screen width itself).现在,您应该传递项目计数和视图大小(通常是屏幕宽度本身),而不是传递项目尺寸。 The item dimension is not needed because it will be calculated internally.不需要项目维度,因为它将在内部计算。

Now always the items will be snaped at the beginning of the view and when scrolling to the last item it will do it smoothly.现在,项目总是会在视图的开头被捕捉,当滚动到最后一个项目时,它会顺利完成。

import 'package:flutter/material.dart';

class PagingScrollPhysics extends ScrollPhysics {
  const PagingScrollPhysics(
      {required this.itemCount, required this.viewSize, super.parent});

  final double viewSize;

  final int itemCount;

  @override
  PagingScrollPhysics applyTo(ScrollPhysics? ancestor) => PagingScrollPhysics(
      itemCount: itemCount, viewSize: viewSize, parent: buildParent(ancestor));

  double _getPage(double current, double itemDimension) =>
      current / itemDimension;

  double _getTargetPixels(
      ScrollMetrics position, Tolerance tolerance, double velocity) {
    // plus view size because the max scroll extent is about where the screen
    //  starts not where the screen ends.
    final pixels = position.maxScrollExtent + viewSize;
    final itemDimension = pixels / itemCount;
    var page = _getPage(position.pixels, itemDimension);
    if (velocity < -tolerance.velocity)
      page -= 0.5;
    else if (velocity > tolerance.velocity) page += 0.5;
    final pageRound = page.round();
    final itemsPerPage = viewSize ~/ itemDimension;
    final showingLastItem = pageRound == itemCount - itemsPerPage;
    if (showingLastItem) return pixels - viewSize;

    return pageRound * itemDimension;
  }

  @override
  Simulation? createBallisticSimulation(
      ScrollMetrics position, double velocity) {
    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 double target = _getTargetPixels(position, tolerance, velocity);
    if (target != position.pixels)
      return ScrollSpringSimulation(spring, position.pixels, target, velocity,
          tolerance: tolerance);
    return null;
  }

  @override
  bool get allowImplicitScrolling => false;
}

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

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