Skip to content

Commit 9d66126

Browse files
AyushBherwani1998Pragya007
authored andcommitted
[ListTile] adds new properties to customize the tile color (flutter#61347)
1 parent 54a9796 commit 9d66126

File tree

2 files changed

+116
-15
lines changed

2 files changed

+116
-15
lines changed

packages/flutter/lib/src/material/list_tile.dart

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,8 @@ class ListTile extends StatelessWidget {
658658
this.hoverColor,
659659
this.focusNode,
660660
this.autofocus = false,
661+
this.tileColor,
662+
this.selectedTileColor,
661663
}) : assert(isThreeLine != null),
662664
assert(enabled != null),
663665
assert(selected != null),
@@ -808,6 +810,16 @@ class ListTile extends StatelessWidget {
808810
/// {@macro flutter.widgets.Focus.autofocus}
809811
final bool autofocus;
810812

813+
/// Defines the background color of `ListTile when [selected] is false.
814+
///
815+
/// By default, the value of `tileColor` is [Colors.transparent].
816+
final Color tileColor;
817+
818+
/// Defines the background color of `ListTile` when [selected] is true.
819+
///
820+
/// By default, the value of `selectedListColor` is [Colors.transparent].
821+
final Color selectedTileColor;
822+
811823
/// Add a one pixel border in between each tile. If color isn't specified the
812824
/// [ThemeData.dividerColor] of the context's [Theme] is used.
813825
///
@@ -913,6 +925,16 @@ class ListTile extends StatelessWidget {
913925
: style.copyWith(color: color);
914926
}
915927

928+
Color _tileBackgroundColor() {
929+
if (!selected && tileColor != null)
930+
return tileColor;
931+
932+
if (selected && selectedTileColor != null)
933+
return selectedTileColor;
934+
935+
return Colors.transparent;
936+
}
937+
916938
@override
917939
Widget build(BuildContext context) {
918940
assert(debugCheckHasMaterial(context));
@@ -984,21 +1006,24 @@ class ListTile extends StatelessWidget {
9841006
child: Semantics(
9851007
selected: selected,
9861008
enabled: enabled,
987-
child: SafeArea(
988-
top: false,
989-
bottom: false,
990-
minimum: resolvedContentPadding,
991-
child: _ListTile(
992-
leading: leadingIcon,
993-
title: titleText,
994-
subtitle: subtitleText,
995-
trailing: trailingIcon,
996-
isDense: _isDenseLayout(tileTheme),
997-
visualDensity: visualDensity ?? theme.visualDensity,
998-
isThreeLine: isThreeLine,
999-
textDirection: textDirection,
1000-
titleBaselineType: titleStyle.textBaseline,
1001-
subtitleBaselineType: subtitleStyle?.textBaseline,
1009+
child: ColoredBox(
1010+
color: _tileBackgroundColor(),
1011+
child: SafeArea(
1012+
top: false,
1013+
bottom: false,
1014+
minimum: resolvedContentPadding,
1015+
child: _ListTile(
1016+
leading: leadingIcon,
1017+
title: titleText,
1018+
subtitle: subtitleText,
1019+
trailing: trailingIcon,
1020+
isDense: _isDenseLayout(tileTheme),
1021+
visualDensity: visualDensity ?? theme.visualDensity,
1022+
isThreeLine: isThreeLine,
1023+
textDirection: textDirection,
1024+
titleBaselineType: titleStyle.textBaseline,
1025+
subtitleBaselineType: subtitleStyle?.textBaseline,
1026+
),
10021027
),
10031028
),
10041029
),

packages/flutter/test/material/list_tile_test.dart

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,4 +1534,80 @@ void main() {
15341534

15351535
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
15361536
});
1537+
1538+
testWidgets('ListTile respects tileColor & selectedTileColor', (WidgetTester tester) async {
1539+
bool isSelected = false;
1540+
const Color selectedTileColor = Colors.red;
1541+
const Color tileColor = Colors.green;
1542+
1543+
await tester.pumpWidget(
1544+
MaterialApp(
1545+
home: Material(
1546+
child: Center(
1547+
child: StatefulBuilder(
1548+
builder: (BuildContext context, StateSetter setState) {
1549+
return ListTile(
1550+
selected: isSelected,
1551+
selectedTileColor: selectedTileColor,
1552+
tileColor: tileColor,
1553+
onTap: () {
1554+
setState(()=> isSelected = !isSelected);
1555+
},
1556+
title: const Text('Title'),
1557+
);
1558+
},
1559+
),
1560+
),
1561+
),
1562+
),
1563+
);
1564+
1565+
// Initially, when isSelected is false, the ListTile should respect tileColor.
1566+
ColoredBox coloredBox = tester.widget(find.byType(ColoredBox));
1567+
expect(coloredBox.color, tileColor);
1568+
1569+
// Tap on tile to change isSelected.
1570+
await tester.tap(find.byType(ListTile));
1571+
await tester.pumpAndSettle();
1572+
1573+
// When isSelected is true, the ListTile should respect selectedTileColor.
1574+
coloredBox = tester.widget(find.byType(ColoredBox));
1575+
expect(coloredBox.color, selectedTileColor);
1576+
});
1577+
1578+
testWidgets('ListTile default tile color', (WidgetTester tester) async {
1579+
bool isSelected = false;
1580+
const Color defaultColor = Colors.transparent;
1581+
1582+
await tester.pumpWidget(
1583+
MaterialApp(
1584+
home: Material(
1585+
child: Center(
1586+
child: StatefulBuilder(
1587+
builder: (BuildContext context, StateSetter setState) {
1588+
return ListTile(
1589+
selected: isSelected,
1590+
onTap: () {
1591+
setState(()=> isSelected = !isSelected);
1592+
},
1593+
title: const Text('Title'),
1594+
);
1595+
},
1596+
),
1597+
),
1598+
),
1599+
),
1600+
);
1601+
1602+
ColoredBox coloredBox = tester.widget(find.byType(ColoredBox));
1603+
expect(coloredBox.color, defaultColor);
1604+
1605+
// Tap on tile to change isSelected.
1606+
await tester.tap(find.byType(ListTile));
1607+
await tester.pumpAndSettle();
1608+
1609+
coloredBox = tester.widget(find.byType(ColoredBox));
1610+
expect(isSelected, isTrue);
1611+
expect(coloredBox.color, defaultColor);
1612+
});
15371613
}

0 commit comments

Comments
 (0)