Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

flutter

I have a PageView/ListView with a viewportFraction of 0.8 to show a preview of the next slide. It looks something like this:

enter image description here

It seems like it is not possible to have the current slide aligned to the left, as shown below. Is that correct?

enter image description here

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.

Is there a way to have the page snapping based on the size of the children?

like image 862
Jonas Avatar asked Oct 15 '25 04:10

Jonas


1 Answers

My answer comes a bit late but it might help others looking for the same thing. the PageScrollPhysics uses the screen width. You need to create your own ScrollPhysics that uses your item width to paginate. 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:

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;
}
like image 63
Alaa Eddine Cherbib Avatar answered Oct 16 '25 22:10

Alaa Eddine Cherbib



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!