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. /// * [CupertinoDialogAction], which is an iOS-style dialog button.
/// * [AlertDialog], a Material Design alert dialog. /// * [AlertDialog], a Material Design alert dialog.
/// * <https://developer.apple.com/ios/human-interface-guidelines/views/alerts/> /// * <https://developer.apple.com/ios/human-interface-guidelines/views/alerts/>
class CupertinoAlertDialog extends StatelessWidget { class CupertinoAlertDialog extends StatefulWidget {
/// Creates an iOS-style alert dialog. /// Creates an iOS-style alert dialog.
/// ///
/// The [actions] must not be null. /// The [actions] must not be null.
@ -233,9 +233,6 @@ class CupertinoAlertDialog extends StatelessWidget {
/// section when there are many actions. /// section when there are many actions.
final ScrollController? scrollController; final ScrollController? scrollController;
ScrollController get _effectiveScrollController =>
scrollController ?? ScrollController();
/// A scroll controller that can be used to control the scrolling of the /// A scroll controller that can be used to control the scrolling of the
/// actions in the dialog. /// actions in the dialog.
/// ///
@ -247,37 +244,49 @@ class CupertinoAlertDialog extends StatelessWidget {
/// section when it is long. /// section when it is long.
final ScrollController? actionScrollController; final ScrollController? actionScrollController;
ScrollController get _effectiveActionScrollController =>
actionScrollController ?? ScrollController();
/// {@macro flutter.material.dialog.insetAnimationDuration} /// {@macro flutter.material.dialog.insetAnimationDuration}
final Duration insetAnimationDuration; final Duration insetAnimationDuration;
/// {@macro flutter.material.dialog.insetAnimationCurve} /// {@macro flutter.material.dialog.insetAnimationCurve}
final Curve 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) { Widget _buildContent(BuildContext context) {
final double textScaleFactor = MediaQuery.textScalerOf(context).textScaleFactor; final double textScaleFactor = MediaQuery.textScalerOf(context).textScaleFactor;
final List<Widget> children = <Widget>[ final List<Widget> children = <Widget>[
if (title != null || content != null) if (widget.title != null || widget.content != null)
Flexible( Flexible(
flex: 3, flex: 3,
child: _CupertinoAlertContentSection( child: _CupertinoAlertContentSection(
title: title, title: widget.title,
message: content, message: widget.content,
scrollController: _effectiveScrollController, scrollController: _effectiveScrollController,
titlePadding: EdgeInsets.only( titlePadding: EdgeInsets.only(
left: _kDialogEdgePadding, left: _kDialogEdgePadding,
right: _kDialogEdgePadding, right: _kDialogEdgePadding,
bottom: content == null ? _kDialogEdgePadding : 1.0, bottom: widget.content == null ? _kDialogEdgePadding : 1.0,
top: _kDialogEdgePadding * textScaleFactor, top: _kDialogEdgePadding * textScaleFactor,
), ),
messagePadding: EdgeInsets.only( messagePadding: EdgeInsets.only(
left: _kDialogEdgePadding, left: _kDialogEdgePadding,
right: _kDialogEdgePadding, right: _kDialogEdgePadding,
bottom: _kDialogEdgePadding * textScaleFactor, bottom: _kDialogEdgePadding * textScaleFactor,
top: title == null ? _kDialogEdgePadding : 1.0, top: widget.title == null ? _kDialogEdgePadding : 1.0,
), ),
titleTextStyle: _kCupertinoDialogTitleStyle.copyWith( titleTextStyle: _kCupertinoDialogTitleStyle.copyWith(
color: CupertinoDynamicColor.resolve(CupertinoColors.label, context), color: CupertinoDynamicColor.resolve(CupertinoColors.label, context),
@ -303,10 +312,10 @@ class CupertinoAlertDialog extends StatelessWidget {
Widget actionSection = Container( Widget actionSection = Container(
height: 0.0, height: 0.0,
); );
if (actions.isNotEmpty) { if (widget.actions.isNotEmpty) {
actionSection = _CupertinoAlertActionSection( actionSection = _CupertinoAlertActionSection(
scrollController: _effectiveActionScrollController, scrollController: _effectiveActionScrollController,
children: actions, children: widget.actions,
); );
} }
@ -330,8 +339,8 @@ class CupertinoAlertDialog extends StatelessWidget {
return AnimatedPadding( return AnimatedPadding(
padding: MediaQuery.viewInsetsOf(context) + padding: MediaQuery.viewInsetsOf(context) +
const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0), const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0),
duration: insetAnimationDuration, duration: widget.insetAnimationDuration,
curve: insetAnimationCurve, curve: widget.insetAnimationCurve,
child: MediaQuery.removeViewInsets( child: MediaQuery.removeViewInsets(
removeLeft: true, removeLeft: true,
removeTop: 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 /// Rounded rectangle surface that looks like an iOS popup surface, e.g., alert dialog

View File

@ -2664,7 +2664,7 @@ void main() {
okNode.dispose(); 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( final AlertDialog dialog = AlertDialog.adaptive(
content: Container( content: Container(
height: 5000.0, height: 5000.0,