-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
Steps to reproduce
- Run the sample code provided below
- Drag the sheet slightly down just enough so that the ballistic simulation gets triggered
- The modal sheet is not dismissed once the ballistic simulation completes. This is caused by the
_DraggableSheetExtent._currentSizenot hitting value of0.0, but instead getting stuck on extremely small values like1.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-17Flutter 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!