Skip to content

Scrollable snapOffsetCallback() physics are wrong #6431

@HansMuller

Description

@HansMuller

The demo below snaps scroll offsets to page boundaries. Scroll deceleration after a fling should match the platform, even when the scroll offset is snapped. It's pretty far off the mark at the moment.

class AnimationDemo extends StatefulWidget {
  static const String routeName = '/animation';

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

class AnimationDemoState extends State<AnimationDemo> {
  final GlobalKey<ScrollableState> _scrollableKey = new GlobalKey<ScrollableState>();
  final List<Color> colors = [
    Colors.red[100],
    Colors.red[200],
    Colors.red[300],
    Colors.red[400],
    Colors.red[500],
    Colors.red[600],
  ];

  Widget _createPage(int i) {
    final double pageWidth = MediaQuery.of(context).size.width;
    return new Container(
      decoration: new BoxDecoration(
        backgroundColor: colors[i]
      ),
      child: new SizedBox(
        width: pageWidth,
        child: new Center(
          child: new Text('Page $i'),
        ),
      ),
    );
  }

  double _snapScrollOffset(double flingScrollOffset, Size containerSize) {
    final double pageWidth = MediaQuery.of(context).size.width;
    final double currentScrollOffset = _scrollableKey.currentState.scrollOffset;
    final int currentPage = (currentScrollOffset / pageWidth).floor();

    // Don't snap overscrolls
    if (currentPage == 0 && flingScrollOffset < currentScrollOffset)
      return flingScrollOffset;
    if (currentPage == 5 && flingScrollOffset > currentScrollOffset)
      return flingScrollOffset;

    final int targetPage = (flingScrollOffset > currentScrollOffset)
      ? (flingScrollOffset / pageWidth).ceil()
      : (flingScrollOffset / pageWidth).floor();
    return targetPage.toDouble() * pageWidth;
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Travel stream'),
      ),
      body: new ScrollableViewport(
        scrollableKey: _scrollableKey,
        scrollDirection: Axis.horizontal,
        snapOffsetCallback: _snapScrollOffset,
        child: new Row(
          children: [0, 1, 2, 3, 4, 5].map(_createPage).toList(),
        ),
      ),
    );
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    f: scrollingViewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions