Skip to content

Commit

Permalink
CupertinoAlertDialog should not create ScrollController on every buil…
Browse files Browse the repository at this point in the history
…d, if null values are passed in constructor. (#133918)
  • Loading branch information
polina-c authored Sep 5, 2023
1 parent c05dc3e commit 7cdf314
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 17 deletions.
48 changes: 32 additions & 16 deletions packages/flutter/lib/src/cupertino/dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ bool _isInAccessibilityMode(BuildContext context) {
/// * [CupertinoDialogAction], which is an iOS-style dialog button.
/// * [AlertDialog], a Material Design alert dialog.
/// * <https://developer.apple.com/ios/human-interface-guidelines/views/alerts/>
class CupertinoAlertDialog extends StatelessWidget {
class CupertinoAlertDialog extends StatefulWidget {
/// Creates an iOS-style alert dialog.
///
/// The [actions] must not be null.
Expand Down Expand Up @@ -233,9 +233,6 @@ class CupertinoAlertDialog extends StatelessWidget {
/// section when there are many actions.
final ScrollController? scrollController;

ScrollController get _effectiveScrollController =>
scrollController ?? ScrollController();

/// A scroll controller that can be used to control the scrolling of the
/// actions in the dialog.
///
Expand All @@ -247,37 +244,49 @@ class CupertinoAlertDialog extends StatelessWidget {
/// section when it is long.
final ScrollController? actionScrollController;

ScrollController get _effectiveActionScrollController =>
actionScrollController ?? ScrollController();

/// {@macro flutter.material.dialog.insetAnimationDuration}
final Duration insetAnimationDuration;

/// {@macro flutter.material.dialog.insetAnimationCurve}
final Curve insetAnimationCurve;

@override
State<CupertinoAlertDialog> createState() => _CupertinoAlertDialogState();
}

class _CupertinoAlertDialogState extends State<CupertinoAlertDialog> {
ScrollController? _backupScrollController;

ScrollController? _backupActionScrollController;

ScrollController get _effectiveScrollController =>
widget.scrollController ?? (_backupScrollController ??= ScrollController());

ScrollController get _effectiveActionScrollController =>
widget.actionScrollController ?? (_backupActionScrollController ??= ScrollController());

Widget _buildContent(BuildContext context) {
final double textScaleFactor = MediaQuery.textScalerOf(context).textScaleFactor;

final List<Widget> children = <Widget>[
if (title != null || content != null)
if (widget.title != null || widget.content != null)
Flexible(
flex: 3,
child: _CupertinoAlertContentSection(
title: title,
message: content,
title: widget.title,
message: widget.content,
scrollController: _effectiveScrollController,
titlePadding: EdgeInsets.only(
left: _kDialogEdgePadding,
right: _kDialogEdgePadding,
bottom: content == null ? _kDialogEdgePadding : 1.0,
bottom: widget.content == null ? _kDialogEdgePadding : 1.0,
top: _kDialogEdgePadding * textScaleFactor,
),
messagePadding: EdgeInsets.only(
left: _kDialogEdgePadding,
right: _kDialogEdgePadding,
bottom: _kDialogEdgePadding * textScaleFactor,
top: title == null ? _kDialogEdgePadding : 1.0,
top: widget.title == null ? _kDialogEdgePadding : 1.0,
),
titleTextStyle: _kCupertinoDialogTitleStyle.copyWith(
color: CupertinoDynamicColor.resolve(CupertinoColors.label, context),
Expand All @@ -303,10 +312,10 @@ class CupertinoAlertDialog extends StatelessWidget {
Widget actionSection = Container(
height: 0.0,
);
if (actions.isNotEmpty) {
if (widget.actions.isNotEmpty) {
actionSection = _CupertinoAlertActionSection(
scrollController: _effectiveActionScrollController,
children: actions,
children: widget.actions,
);
}

Expand All @@ -330,8 +339,8 @@ class CupertinoAlertDialog extends StatelessWidget {
return AnimatedPadding(
padding: MediaQuery.viewInsetsOf(context) +
const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0),
duration: insetAnimationDuration,
curve: insetAnimationCurve,
duration: widget.insetAnimationDuration,
curve: widget.insetAnimationCurve,
child: MediaQuery.removeViewInsets(
removeLeft: true,
removeTop: true,
Expand Down Expand Up @@ -368,6 +377,13 @@ class CupertinoAlertDialog extends StatelessWidget {
),
);
}

@override
void dispose() {
_backupScrollController?.dispose();
_backupActionScrollController?.dispose();
super.dispose();
}
}

/// Rounded rectangle surface that looks like an iOS popup surface, e.g., alert dialog
Expand Down
2 changes: 1 addition & 1 deletion packages/flutter/test/material/dialog_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2664,7 +2664,7 @@ void main() {
okNode.dispose();
});

testWidgets('Adaptive AlertDialog shows correct widget on each platform', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Adaptive AlertDialog shows correct widget on each platform', (WidgetTester tester) async {
final AlertDialog dialog = AlertDialog.adaptive(
content: Container(
height: 5000.0,
Expand Down

0 comments on commit 7cdf314

Please sign in to comment.