Skip to content

Commit 8384f1e

Browse files
author
Casey Hillers
authored
Revert DraggableScrollableSheet controller changes (#112293)
1 parent 4ceeca0 commit 8384f1e

File tree

2 files changed

+31
-114
lines changed

2 files changed

+31
-114
lines changed

packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import 'scroll_physics.dart';
2121
import 'scroll_position.dart';
2222
import 'scroll_position_with_single_context.dart';
2323
import 'scroll_simulation.dart';
24-
import 'value_listenable_builder.dart';
2524

2625
/// The signature of a method that provides a [BuildContext] and
2726
/// [ScrollController] for building a widget that may overflow the draggable
@@ -489,6 +488,7 @@ class _DraggableSheetExtent {
489488
required this.snap,
490489
required this.snapSizes,
491490
required this.initialSize,
491+
required this.onSizeChanged,
492492
this.snapAnimationDuration,
493493
ValueNotifier<double>? currentSize,
494494
bool? hasDragged,
@@ -500,7 +500,8 @@ class _DraggableSheetExtent {
500500
assert(maxSize <= 1),
501501
assert(minSize <= initialSize),
502502
assert(initialSize <= maxSize),
503-
_currentSize = currentSize ?? ValueNotifier<double>(initialSize),
503+
_currentSize = (currentSize ?? ValueNotifier<double>(initialSize))
504+
..addListener(onSizeChanged),
504505
availablePixels = double.infinity,
505506
hasDragged = hasDragged ?? false,
506507
hasChanged = hasChanged ?? false;
@@ -514,6 +515,7 @@ class _DraggableSheetExtent {
514515
final Duration? snapAnimationDuration;
515516
final double initialSize;
516517
final ValueNotifier<double> _currentSize;
518+
final VoidCallback onSizeChanged;
517519
double availablePixels;
518520

519521
// Used to disable snapping until the user has dragged on the sheet.
@@ -593,12 +595,17 @@ class _DraggableSheetExtent {
593595
return size / maxSize * availablePixels;
594596
}
595597

598+
void dispose() {
599+
_currentSize.removeListener(onSizeChanged);
600+
}
601+
596602
_DraggableSheetExtent copyWith({
597603
required double minSize,
598604
required double maxSize,
599605
required bool snap,
600606
required List<double> snapSizes,
601607
required double initialSize,
608+
required VoidCallback onSizeChanged,
602609
Duration? snapAnimationDuration,
603610
}) {
604611
return _DraggableSheetExtent(
@@ -608,6 +615,7 @@ class _DraggableSheetExtent {
608615
snapSizes: snapSizes,
609616
snapAnimationDuration: snapAnimationDuration,
610617
initialSize: initialSize,
618+
onSizeChanged: onSizeChanged,
611619
// Set the current size to the possibly updated initial size if the sheet
612620
// hasn't changed yet.
613621
currentSize: ValueNotifier<double>(hasChanged
@@ -633,6 +641,7 @@ class _DraggableScrollableSheetState extends State<DraggableScrollableSheet> {
633641
snapSizes: _impliedSnapSizes(),
634642
snapAnimationDuration: widget.snapAnimationDuration,
635643
initialSize: widget.initialChildSize,
644+
onSizeChanged: _setExtent,
636645
);
637646
_scrollController = _DraggableScrollableSheetScrollController(extent: _extent);
638647
widget.controller?._attach(_scrollController);
@@ -663,10 +672,6 @@ class _DraggableScrollableSheetState extends State<DraggableScrollableSheet> {
663672
@override
664673
void didUpdateWidget(covariant DraggableScrollableSheet oldWidget) {
665674
super.didUpdateWidget(oldWidget);
666-
if (widget.controller != oldWidget.controller) {
667-
oldWidget.controller?._detach();
668-
widget.controller?._attach(_scrollController);
669-
}
670675
_replaceExtent(oldWidget);
671676
}
672677

@@ -678,50 +683,53 @@ class _DraggableScrollableSheetState extends State<DraggableScrollableSheet> {
678683
}
679684
}
680685

686+
void _setExtent() {
687+
setState(() {
688+
// _extent has been updated when this is called.
689+
});
690+
}
691+
681692
@override
682693
Widget build(BuildContext context) {
683-
return ValueListenableBuilder<double>(
684-
valueListenable: _extent._currentSize,
685-
builder: (BuildContext context, double currentSize, Widget? child) => LayoutBuilder(
686-
builder: (BuildContext context, BoxConstraints constraints) {
687-
_extent.availablePixels = widget.maxChildSize * constraints.biggest.height;
688-
final Widget sheet = FractionallySizedBox(
689-
heightFactor: currentSize,
690-
alignment: Alignment.bottomCenter,
691-
child: child,
692-
);
693-
return widget.expand ? SizedBox.expand(child: sheet) : sheet;
694-
},
695-
),
696-
child: widget.builder(context, _scrollController),
694+
return LayoutBuilder(
695+
builder: (BuildContext context, BoxConstraints constraints) {
696+
_extent.availablePixels = widget.maxChildSize * constraints.biggest.height;
697+
final Widget sheet = FractionallySizedBox(
698+
heightFactor: _extent.currentSize,
699+
alignment: Alignment.bottomCenter,
700+
child: widget.builder(context, _scrollController),
701+
);
702+
return widget.expand ? SizedBox.expand(child: sheet) : sheet;
703+
},
697704
);
698705
}
699706

700707
@override
701708
void dispose() {
702709
widget.controller?._detach();
703710
_scrollController.dispose();
711+
_extent.dispose();
704712
super.dispose();
705713
}
706714

707715
void _replaceExtent(covariant DraggableScrollableSheet oldWidget) {
708716
final _DraggableSheetExtent previousExtent = _extent;
717+
_extent.dispose();
709718
_extent = _extent.copyWith(
710719
minSize: widget.minChildSize,
711720
maxSize: widget.maxChildSize,
712721
snap: widget.snap,
713722
snapSizes: _impliedSnapSizes(),
714723
snapAnimationDuration: widget.snapAnimationDuration,
715724
initialSize: widget.initialChildSize,
725+
onSizeChanged: _setExtent,
716726
);
717727
// Modify the existing scroll controller instead of replacing it so that
718728
// developers listening to the controller do not have to rebuild their listeners.
719729
_scrollController.extent = _extent;
720730
// If an external facing controller was provided, let it know that the
721731
// extent has been replaced.
722-
if (widget.controller == oldWidget.controller) {
723-
widget.controller?._onExtentReplaced(previousExtent);
724-
}
732+
widget.controller?._onExtentReplaced(previousExtent);
725733
if (widget.snap
726734
&& (widget.snap != oldWidget.snap || widget.snapSizes != oldWidget.snapSizes)
727735
&& _scrollController.hasClients

packages/flutter/test/widgets/draggable_scrollable_sheet_test.dart

Lines changed: 0 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,95 +1465,4 @@ void main() {
14651465
closeTo(.6, precisionErrorTolerance),
14661466
);
14671467
});
1468-
1469-
testWidgets('DraggableScrollableSheet should not rebuild every frame while dragging', (WidgetTester tester) async {
1470-
// Regression test for https://github.com/flutter/flutter/issues/67219
1471-
int buildCount = 0;
1472-
await tester.pumpWidget(MaterialApp(
1473-
home: StatefulBuilder(
1474-
builder: (BuildContext context, StateSetter setState) => Scaffold(
1475-
body: DraggableScrollableSheet(
1476-
initialChildSize: 0.25,
1477-
snap: true,
1478-
snapSizes: const <double>[0.25, 0.5, 1.0],
1479-
builder: (BuildContext context, ScrollController scrollController) {
1480-
buildCount++;
1481-
return ListView(
1482-
controller: scrollController,
1483-
children: <Widget>[
1484-
const Text('Drag me!'),
1485-
ElevatedButton(
1486-
onPressed: () => setState(() {}),
1487-
child: const Text('Rebuild'),
1488-
),
1489-
Container(
1490-
height: 10000,
1491-
color: Colors.blue,
1492-
),
1493-
],
1494-
);
1495-
},
1496-
),
1497-
),
1498-
),
1499-
));
1500-
1501-
expect(buildCount, 1);
1502-
1503-
await tester.fling(find.text('Drag me!'), const Offset(0, -300), 300);
1504-
await tester.pumpAndSettle();
1505-
1506-
// No need to rebuild the scrollable sheet, as only position has changed.
1507-
expect(buildCount, 1);
1508-
1509-
await tester.tap(find.text('Rebuild'));
1510-
await tester.pump();
1511-
1512-
// DraggableScrollableSheet has rebuilt, so expect the builder to be called.
1513-
expect(buildCount, 2);
1514-
});
1515-
1516-
testWidgets('DraggableScrollableSheet controller can be changed', (WidgetTester tester) async {
1517-
final DraggableScrollableController controller1 = DraggableScrollableController();
1518-
final DraggableScrollableController controller2 = DraggableScrollableController();
1519-
DraggableScrollableController controller = controller1;
1520-
await tester.pumpWidget(MaterialApp(
1521-
home: StatefulBuilder(
1522-
builder: (BuildContext context, StateSetter setState) => Scaffold(
1523-
body: DraggableScrollableSheet(
1524-
initialChildSize: 0.25,
1525-
snap: true,
1526-
snapSizes: const <double>[0.25, 0.5, 1.0],
1527-
controller: controller,
1528-
builder: (BuildContext context, ScrollController scrollController) {
1529-
return ListView(
1530-
controller: scrollController,
1531-
children: <Widget>[
1532-
ElevatedButton(
1533-
onPressed: () => setState(() {
1534-
controller = controller2;
1535-
}),
1536-
child: const Text('Switch controller'),
1537-
),
1538-
Container(
1539-
height: 10000,
1540-
color: Colors.blue,
1541-
),
1542-
],
1543-
);
1544-
},
1545-
),
1546-
),
1547-
),
1548-
));
1549-
1550-
expect(controller1.isAttached, true);
1551-
expect(controller2.isAttached, false);
1552-
1553-
await tester.tap(find.text('Switch controller'));
1554-
await tester.pump();
1555-
1556-
expect(controller1.isAttached, false);
1557-
expect(controller2.isAttached, true);
1558-
});
15591468
}

0 commit comments

Comments
 (0)