diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart
index ef8c10936043..2e4d27af7574 100644
--- a/packages/flutter/lib/src/cupertino/dialog.dart
+++ b/packages/flutter/lib/src/cupertino/dialog.dart
@@ -188,7 +188,7 @@ bool _isInAccessibilityMode(BuildContext context) {
/// * [CupertinoDialogAction], which is an iOS-style dialog button.
/// * [AlertDialog], a Material Design alert dialog.
/// *
-class CupertinoAlertDialog extends StatelessWidget {
+class CupertinoAlertDialog extends StatefulWidget {
/// Creates an iOS-style alert dialog.
///
/// The [actions] must not be null.
@@ -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.
///
@@ -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 createState() => _CupertinoAlertDialogState();
+}
+
+class _CupertinoAlertDialogState extends State {
+ 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 children = [
- 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),
@@ -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,
);
}
@@ -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,
@@ -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
diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart
index d26707e98629..5e8d9f2ff963 100644
--- a/packages/flutter/test/material/dialog_test.dart
+++ b/packages/flutter/test/material/dialog_test.dart
@@ -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,