Skip to content

DraggableScrollableSheet _DraggableSheetExtent not reaching 0 during _SnappingSimulation #140701

@vongrad

Description

@vongrad

Steps to reproduce

  1. Run the sample code provided below
  2. Drag the sheet slightly down just enough so that the ballistic simulation gets triggered
  3. The modal sheet is not dismissed once the ballistic simulation completes. This is caused by the _DraggableSheetExtent._currentSize not hitting value of 0.0, but instead getting stuck on extremely small values like 1.3877787807814457e-17

Expected results

The modal sheet is dismissed once the ballistic simulation completes.

Actual results

The modal sheet is visible once the ballistic simulation completes. This does not happen always, but I can reproduce it about 1/4 of the time.

I believe the issue is within _DraggableScrollableSheetScrollPosition, specifically in goBallistic function. When using the extent.snap, we use _SnappingSimulation, which seems to be working fine. However a few lines further, a tick function is defined, where a delta is added to the current extent value:

void tick() {
      final double delta = ballisticController.value - lastPosition;
      lastPosition = ballisticController.value;
      extent.addPixelDelta(delta, context.notificationContext!);
      if ((velocity > 0 && extent.isAtMax) || (velocity < 0 && extent.isAtMin)) {
        // Make sure we pass along enough velocity to keep scrolling - otherwise
        // we just "bounce" off the top making it look like the list doesn't
        // have more to scroll.
        velocity = ballisticController.velocity + (physics.toleranceFor(this).velocity * ballisticController.velocity.sign);
        super.goBallistic(velocity);
        ballisticController.stop();
      } else if (ballisticController.isCompleted) {
        super.goBallistic(0);
      }
}

I believe we could fix it in else if (ballisticController.isCompleted) by checking if the extent value is very close to zero (x <= 0.01) and if so, rounding it to 0.0. I however do not think this would be the right fix and we should rather see why we do not hit exact 0. This could perhaps be caused by pixelsToSize where the availablePixels are off by 1 or so.

Code sample

Code sample
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Draggable Sheet Bug"),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          showModalBottomSheet(
              useSafeArea: true,
              isScrollControlled: true,
              backgroundColor: Colors.transparent,
              context: context,
              builder: (context) {
                return const ModalSheet();
              });
        },
        tooltip: 'Show',
        child: const Icon(Icons.add),
      ),
    );
  }
}

class ModalSheet extends StatelessWidget {
  const ModalSheet({super.key});

  @override
  Widget build(BuildContext context) {
    return NotificationListener<DraggableScrollableNotification>(
      onNotification: (notification) {
        print(notification.extent);
        return false;
      },
      child: DraggableScrollableSheet(
        shouldCloseOnMinExtent: true,
        minChildSize: 0,
        initialChildSize: 1,
        maxChildSize: 1,
        snapSizes: const [],
        expand: true,
        snap: true,
        builder: (context, scrollController) {
          return ListView.separated(
              controller: scrollController,
              itemBuilder: (context, index) {
                return Container(
                  height: 100,
                  color: Colors.red,
                  child: Text('Item $index'),
                );
              },
              itemCount: 20,
              separatorBuilder: (context, index) {
                return const SizedBox(
                  height: 2,
                );
              });
        },
      ),
    );
  }
}

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Simulator.Screen.Recording.-.iPhone.15.Pro.-.2023-12-28.at.16.31.00.mp4

Logs

These are the extent values obtained from DraggableScrollableNotification
NotificationListener<DraggableScrollableNotification>(
      onNotification: (notification) {
        print(notification.extent);
        return false;
      }
)

As you can see, the extent never reaches 0.0 and stays on 3.122502256758253e-17 value

flutter: 0.9985287936107609
flutter: 0.9733081126523749
flutter: 0.9182429528126149
flutter: 0.8879781356625519
flutter: 0.8543398002274951
flutter: 0.8207135707192983
flutter: 0.7870893588655783
flutter: 0.7534530410849982
flutter: 0.7198288292312782
flutter: 0.6862005820686049
flutter: 0.6525763702148849
flutter: 0.6189501407066882
flutter: 0.5853239111984915
flutter: 0.5516996993447714
flutter: 0.5180694345276213
flutter: 0.4844391697104713
flutter: 0.45081495785675124
flutter: 0.41718671069407787
flutter: 0.38355241056797434
flutter: 0.3499221457508243
flutter: 0.3162959162426276
flutter: 0.28267372204338426
flutter: 0.2490474925351875
flutter: 0.2154192453725141
flutter: 0.18178898055536402
flutter: 0.14816678635612057
flutter: 0.11452845092106395
flutter: 0.08090423906734392
flutter: 0.04727599190467041
flutter: 0.013639674124090381
flutter: 3.122502256758253e-17
flutter: 3.122502256758253e-17

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.16.0, on macOS 14.2.1 23C71 darwin-arm64, locale en-DK)
    • Flutter version 3.16.0 on channel stable at /Users/vongrad/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision db7ef5bf9f (6 weeks ago), 2023-11-15 11:25:44 -0800
    • Engine revision 74d16627b9
    • Dart version 3.2.0
    • DevTools version 2.28.2

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/vongrad/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = /Users/vongrad/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15C65
    • CocoaPods version 1.14.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2023.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)

[✓] Connected device (4 available)
    • vongrad (mobile)       • 00008120-001814C13683C01E            • ios            • iOS 17.1.2 21B101
    • iPhone 15 Pro (mobile) • 3ED33087-E9F9-44EA-B99B-EAF7641B486E • ios            • com.apple.CoreSimulator.SimRuntime.iOS-17-2 (simulator)
    • macOS (desktop)        • macos                                • darwin-arm64   • macOS 14.2.1 23C71 darwin-arm64
    • Chrome (web)           • chrome                               • web-javascript • Google Chrome 120.0.6099.129

[✓] Network resources
    • All expected network resources are available.

• No issues found!

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projectf: scrollingViewports, list views, slivers, etc.found in release: 3.16Found to occur in 3.16found in release: 3.18Found to occur in 3.18frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer versionteam-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions