Skip to content

Instantly share code, notes, and snippets.

@rolurq
Created August 16, 2019 22:18
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rolurq/5db4c0cb7db66cf8f5a59396faeec7fa to your computer and use it in GitHub Desktop.
Save rolurq/5db4c0cb7db66cf8f5a59396faeec7fa to your computer and use it in GitHub Desktop.
Paged scrollable in flutter that doesn't center the edge elements
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
final List<int> pages = List.generate(4, (index) => index);
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView.builder(
scrollDirection: Axis.horizontal,
physics: CustomScrollPhysics(itemDimension: 300),
itemCount: pages.length,
itemBuilder: (context, index) => Container(
height: double.infinity,
width: 290,
color: randomColor,
margin: const EdgeInsets.only(right: 10),
),
),
),
);
}
Color get randomColor =>
Color((Random().nextDouble() * 0xFFFFFF).toInt() << 0).withOpacity(1.0);
}
class CustomScrollPhysics extends ScrollPhysics {
final double itemDimension;
CustomScrollPhysics({this.itemDimension, ScrollPhysics parent})
: super(parent: parent);
@override
CustomScrollPhysics applyTo(ScrollPhysics ancestor) {
return CustomScrollPhysics(
itemDimension: itemDimension, parent: buildParent(ancestor));
}
double _getPage(ScrollPosition position, double portion) {
return (position.pixels + portion) / itemDimension;
}
double _getPixels(double page, double portion) {
return (page * itemDimension) - portion;
}
double _getTargetPixels(
ScrollPosition 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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment