diff --git a/packages/flutter/lib/src/cupertino/list_tile.dart b/packages/flutter/lib/src/cupertino/list_tile.dart index cf0be02ce3e..e14f656da71 100644 --- a/packages/flutter/lib/src/cupertino/list_tile.dart +++ b/packages/flutter/lib/src/cupertino/list_tile.dart @@ -308,7 +308,7 @@ class _CupertinoListTileState extends State { // null and it will resolve to the correct color provided by context. But if // the tile was tapped, it is set to what user provided or if null to the // default color that matched the iOS-style. - Color? backgroundColor = widget.backgroundColor; + Color backgroundColor = widget.backgroundColor ?? CupertinoColors.transparent; if (_tapped) { backgroundColor = widget.backgroundColorActivated ?? CupertinoColors.systemGrey4.resolveFrom(context); @@ -321,44 +321,46 @@ class _CupertinoListTileState extends State { _CupertinoListTileType.notched => _kNotchedMinHeightWithoutLeading, }; - final Widget child = Container( + final Widget child = ConstrainedBox( constraints: BoxConstraints(minWidth: double.infinity, minHeight: minHeight), - color: backgroundColor, - child: Padding( - padding: padding, - child: Row( - children: [ - if (widget.leading case final Widget leading) ...[ - SizedBox.square(dimension: widget.leadingSize, child: Center(child: leading)), - SizedBox(width: widget.leadingToTitle), - ] else - SizedBox(height: widget.leadingSize), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - title, - if (widget.subtitle case final Widget subtitle) ...[ - const SizedBox(height: _kNotchedTitleToSubtitle), - DefaultTextStyle( - style: coloredStyle.copyWith( - fontSize: baseType ? _kSubtitleFontSize : _kNotchedSubtitleFontSize, + child: ColoredBox( + color: backgroundColor, + child: Padding( + padding: padding, + child: Row( + children: [ + if (widget.leading case final Widget leading) ...[ + SizedBox.square(dimension: widget.leadingSize, child: Center(child: leading)), + SizedBox(width: widget.leadingToTitle), + ] else + SizedBox(height: widget.leadingSize), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + title, + if (widget.subtitle case final Widget subtitle) ...[ + const SizedBox(height: _kNotchedTitleToSubtitle), + DefaultTextStyle( + style: coloredStyle.copyWith( + fontSize: baseType ? _kSubtitleFontSize : _kNotchedSubtitleFontSize, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + child: subtitle, ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - child: subtitle, - ), + ], ], - ], + ), ), - ), - if (widget.additionalInfo case final Widget additionalInfo) ...[ - DefaultTextStyle(style: coloredStyle, maxLines: 1, child: additionalInfo), - if (widget.trailing != null) const SizedBox(width: _kAdditionalInfoToTrailing), + if (widget.additionalInfo case final Widget additionalInfo) ...[ + DefaultTextStyle(style: coloredStyle, maxLines: 1, child: additionalInfo), + if (widget.trailing != null) const SizedBox(width: _kAdditionalInfoToTrailing), + ], + if (widget.trailing != null) widget.trailing!, ], - if (widget.trailing != null) widget.trailing!, - ], + ), ), ), ); diff --git a/packages/flutter/test/cupertino/list_tile_test.dart b/packages/flutter/test/cupertino/list_tile_test.dart index 559b619781a..3e572cdfa42 100644 --- a/packages/flutter/test/cupertino/list_tile_test.dart +++ b/packages/flutter/test/cupertino/list_tile_test.dart @@ -89,9 +89,10 @@ void main() { ), ); - // Container inside CupertinoListTile is the second one in row. - final Container container = tester.widgetList(find.byType(Container)).elementAt(1); - expect(container.color, backgroundColor); + final ColoredBox coloredBox = tester.widget( + find.descendant(of: find.byType(CupertinoListTile), matching: find.byType(ColoredBox)), + ); + expect(coloredBox.color, backgroundColor); }); testWidgets('does not change backgroundColor when tapped if onTap is not provided', ( @@ -121,9 +122,10 @@ void main() { await tester.tap(find.byType(CupertinoListTile)); await tester.pump(); - // Container inside CupertinoListTile is the second one in row. - final Container container = tester.widgetList(find.byType(Container)).elementAt(1); - expect(container.color, backgroundColor); + final ColoredBox coloredBox = tester.widget( + find.descendant(of: find.byType(CupertinoListTile), matching: find.byType(ColoredBox)), + ); + expect(coloredBox.color, backgroundColor); }); testWidgets('changes backgroundColor when tapped if onTap is provided', ( @@ -153,17 +155,19 @@ void main() { ), ); - // Container inside CupertinoListTile is the second one in row. - Container container = tester.widgetList(find.byType(Container)).elementAt(1); - expect(container.color, backgroundColor); + ColoredBox coloredBox = tester.widget( + find.descendant(of: find.byType(CupertinoListTile), matching: find.byType(ColoredBox)), + ); + expect(coloredBox.color, backgroundColor); // Pump only one frame so the color change persists. await tester.tap(find.byType(CupertinoListTile)); await tester.pump(); - // Container inside CupertinoListTile is the second one in row. - container = tester.widgetList(find.byType(Container)).elementAt(1); - expect(container.color, backgroundColorActivated); + coloredBox = tester.widget( + find.descendant(of: find.byType(CupertinoListTile), matching: find.byType(ColoredBox)), + ); + expect(coloredBox.color, backgroundColorActivated); // Pump the rest of the frames to complete the test. await tester.pumpAndSettle(); @@ -184,7 +188,6 @@ void main() { ), ); - // Container inside CupertinoListTile is the second one in row. expect(find.byType(GestureDetector), findsNothing); }); @@ -203,7 +206,6 @@ void main() { ), ); - // Container inside CupertinoListTile is the second one in row. expect(find.byType(GestureDetector), findsOneWidget); }); @@ -251,9 +253,10 @@ void main() { await tester.tap(find.byType(CupertinoButton)); await tester.pumpAndSettle(); - // Container inside CupertinoListTile is the second one in row. - final Container container = tester.widget(find.byType(Container)); - expect(container.color, backgroundColor); + final ColoredBox coloredBox = tester.widget( + find.descendant(of: find.byType(CupertinoListTile), matching: find.byType(ColoredBox)), + ); + expect(coloredBox.color, backgroundColor); }); group('alignment of widgets for left-to-right', () { @@ -494,4 +497,49 @@ void main() { expect(tester.takeException(), null); }); + + testWidgets('Leading and trailing animate on listtile long press', (WidgetTester tester) async { + bool value = false; + await tester.pumpWidget( + CupertinoApp( + home: CupertinoPageScaffold( + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return CupertinoListTile( + title: const Text(''), + onTap: + () => setState(() { + value = !value; + }), + leading: CupertinoSwitch(value: value, onChanged: (_) {}), + trailing: CupertinoSwitch(value: value, onChanged: (_) {}), + ); + }, + ), + ), + ), + ); + + final CurvedAnimation firstPosition = + (tester.state(find.byType(CupertinoSwitch).first) as dynamic).position as CurvedAnimation; + final CurvedAnimation lastPosition = + (tester.state(find.byType(CupertinoSwitch).last) as dynamic).position as CurvedAnimation; + + expect(firstPosition.value, 0.0); + expect(lastPosition.value, 0.0); + + await tester.longPress(find.byType(CupertinoListTile)); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 65)); + + expect(firstPosition.value, greaterThan(0.0)); + expect(lastPosition.value, greaterThan(0.0)); + + expect(firstPosition.value, lessThan(1.0)); + expect(lastPosition.value, lessThan(1.0)); + + await tester.pumpAndSettle(); + expect(firstPosition.value, 1.0); + expect(lastPosition.value, 1.0); + }); }