Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter: Add friction to user scrolling, not spring

I have a list view with a custom scroll physics class that defines how I want the scrolling and spring effects of a list I have. I have managed to set the spring dampening the way I want it but I can't seem to find any settings around the making the drag heavier for the user.

What I mean by that is when the user drags I want the list to feel like it has tension so the user needs to drag further than they normally would I and I will handle the movement to the next item in the list using the custom scroll physics.

I want it to feel like a turn style at a train station. There is lots of tension you receive with your body and once you pass through the turn style resets itself to center.

List:

child: ListView.builder(
  cacheExtent: MediaQuery.of(context).size.height * 2,
  padding: EdgeInsets.only(top: 0),
  itemExtent: constraints.maxHeight -
      SizeConfig.blockSizeVertical * 40,
  itemCount: channelList?.length ?? 0,
  controller: _controller,
  physics: _physics,
  itemBuilder: (BuildContext context, int index) =>
      buildList(index),
),

Custom scroll class:

import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';

class CustomScrollPhysics extends ScrollPhysics {
  final double itemDimension;
  static final SpringDescription customSpring =
      SpringDescription.withDampingRatio(
    mass: 4,
    stiffness: 150.0,
    ratio: 2.0,
  );

  @override
  double get dragStartDistanceMotionThreshold => 40;

  @override
  double get minFlingVelocity => double.infinity;

  @override
  double get maxFlingVelocity => double.infinity;

  @override
  double get minFlingDistance => double.infinity;

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

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

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

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

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

  @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 an item 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 double target = _getTargetPixels(position, tolerance, velocity);
    if (target != position.pixels) {
      return ScrollSpringSimulation(
          customSpring, position.pixels, target, velocity,
          tolerance: tolerance);
    }
    return null;
  }

  @override
  bool get allowImplicitScrolling => false;
}

/// Note: This Widget creates the ballistics model for a snap-to physics in a ListView.
/// Normally you might use the ListViewScrollView, however that widget currently
/// has a bug that prevents onTap detection of child widgets.

The list is centered on the screen and roughly 60% of the view height.

like image 594
theblindprophet Avatar asked Oct 10 '20 14:10

theblindprophet


People also ask

What is BouncingScrollPhysics flutter?

BouncingScrollPhysics class Null safety. Scroll physics for environments that allow the scroll offset to go beyond the bounds of the content, but then bounce the content back to the edge of those bounds. This is the behavior typically seen on iOS.


1 Answers

If you only need to display one item in the list at a time and the rendering of an item will fit on the screen, using a PageView widget might give you the effect that you are after.

like image 94
Jannie Theunissen Avatar answered Sep 19 '22 09:09

Jannie Theunissen