CupertinoAlertDialog should not create ScrollController on every build, if null values are passed in constructor. (#134075)

Relanding of https://github.com/flutter/flutter/pull/134071

Verified failed tests succeeded now:
This commit is contained in:
Polina Cherkasova 2023-09-07 16:59:58 -07:00 committed by GitHub
parent a863ad6e76
commit cc95ace32c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 17 deletions

View File

@ -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.
@ -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<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),
@ -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

View File

@ -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,