Skip to content

Commit c02d22d

Browse files
authored
feat(SwitchListTile): ensure that 'isThreeLine' can be configured through the theme. (flutter#166820)
This PR is a continuation of [165481](flutter#165481) Related items also include: [RadioListTile](flutter#166964), [CheckboxListTile](flutter#166826) ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing.
1 parent d80c390 commit c02d22d

File tree

3 files changed

+241
-9
lines changed

3 files changed

+241
-9
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ class ListTileThemeData with Diagnosticable {
140140
/// or [ExpansionTile.controlAffinity] or [SwitchListTile.controlAffinity] or [RadioListTile.controlAffinity].
141141
final ListTileControlAffinity? controlAffinity;
142142

143-
/// If specified, overrides the default value of [ListTile.isThreeLine] or [CheckboxListTile.isThreeLine]
144-
/// or [RadioListTile.isThreeLine].
143+
/// If specified, overrides the default value of [ListTile.isThreeLine]
144+
/// or [CheckboxListTile.isThreeLine] or [RadioListTile.isThreeLine] or [SwitchListTile.isThreeLine].
145145
final bool? isThreeLine;
146146

147147
/// Creates a copy of this object with the given fields replaced with the

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ class SwitchListTile extends StatelessWidget {
203203
this.tileColor,
204204
this.title,
205205
this.subtitle,
206-
this.isThreeLine = false,
206+
this.isThreeLine,
207207
this.dense,
208208
this.contentPadding,
209209
this.secondary,
@@ -219,7 +219,7 @@ class SwitchListTile extends StatelessWidget {
219219
applyCupertinoTheme = false,
220220
assert(activeThumbImage != null || onActiveThumbImageError == null),
221221
assert(inactiveThumbImage != null || onInactiveThumbImageError == null),
222-
assert(!isThreeLine || subtitle != null);
222+
assert(isThreeLine != true || subtitle != null);
223223

224224
/// Creates a Material [ListTile] with an adaptive [Switch], following
225225
/// Material design's
@@ -266,7 +266,7 @@ class SwitchListTile extends StatelessWidget {
266266
this.tileColor,
267267
this.title,
268268
this.subtitle,
269-
this.isThreeLine = false,
269+
this.isThreeLine,
270270
this.dense,
271271
this.contentPadding,
272272
this.secondary,
@@ -279,7 +279,7 @@ class SwitchListTile extends StatelessWidget {
279279
this.hoverColor,
280280
this.internalAddSemanticForOnTap = false,
281281
}) : _switchListTileType = _SwitchListTileType.adaptive,
282-
assert(!isThreeLine || subtitle != null),
282+
assert(isThreeLine != true || subtitle != null),
283283
assert(activeThumbImage != null || onActiveThumbImageError == null),
284284
assert(inactiveThumbImage != null || onInactiveThumbImageError == null);
285285

@@ -479,9 +479,10 @@ class SwitchListTile extends StatelessWidget {
479479

480480
/// Whether this list tile is intended to display three lines of text.
481481
///
482-
/// If false, the list tile is treated as having one line if the subtitle is
483-
/// null and treated as having two lines if the subtitle is non-null.
484-
final bool isThreeLine;
482+
/// If null, the value from [ListTileThemeData.isThreeLine] is used.
483+
/// If that is also null, the value from [ThemeData.listTileTheme] is used.
484+
/// If still null, the default value is `false`.
485+
final bool? isThreeLine;
485486

486487
/// Whether this list tile is part of a vertically dense list.
487488
///

packages/flutter/test/material/switch_list_tile_test.dart

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,6 +1891,237 @@ void main() {
18911891
expect(offsetPlatform, const Offset(16.0, 16.0));
18921892
});
18931893

1894+
testWidgets('SwitchListTile isThreeLine', (WidgetTester tester) async {
1895+
const double height = 300;
1896+
const double switchTop = 130.0;
1897+
1898+
Widget buildFrame({bool? themeDataIsThreeLine, bool? themeIsThreeLine, bool? isThreeLine}) {
1899+
return MaterialApp(
1900+
key: UniqueKey(),
1901+
theme:
1902+
themeDataIsThreeLine != null
1903+
? ThemeData(listTileTheme: ListTileThemeData(isThreeLine: themeDataIsThreeLine))
1904+
: null,
1905+
home: Material(
1906+
child: ListTileTheme(
1907+
data:
1908+
themeIsThreeLine != null ? ListTileThemeData(isThreeLine: themeIsThreeLine) : null,
1909+
child: ListView(
1910+
children: <Widget>[
1911+
SwitchListTile(
1912+
isThreeLine: isThreeLine,
1913+
title: const Text('A'),
1914+
subtitle: const Text('A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM'),
1915+
value: false,
1916+
onChanged: null,
1917+
),
1918+
SwitchListTile(
1919+
isThreeLine: isThreeLine,
1920+
title: const Text('A'),
1921+
subtitle: const Text('A'),
1922+
value: false,
1923+
onChanged: null,
1924+
),
1925+
],
1926+
),
1927+
),
1928+
),
1929+
);
1930+
}
1931+
1932+
void expectTwoLine() {
1933+
expect(
1934+
tester.getRect(find.byType(SwitchListTile).at(0)),
1935+
const Rect.fromLTWH(0.0, 0.0, 800.0, height),
1936+
);
1937+
expect(
1938+
tester.getRect(find.byType(Switch).at(0)),
1939+
const Rect.fromLTWH(800.0 - 60.0 - 24.0, switchTop, 60.0, 40.0),
1940+
);
1941+
expect(
1942+
tester.getRect(find.byType(SwitchListTile).at(1)),
1943+
const Rect.fromLTWH(0.0, height, 800.0, 72.0),
1944+
);
1945+
expect(
1946+
tester.getRect(find.byType(Switch).at(1)),
1947+
const Rect.fromLTWH(800.0 - 60.0 - 24.0, height + 16, 60.0, 40.0),
1948+
);
1949+
}
1950+
1951+
void expectThreeLine() {
1952+
expect(
1953+
tester.getRect(find.byType(SwitchListTile).at(0)),
1954+
const Rect.fromLTWH(0.0, 0.0, 800.0, height),
1955+
);
1956+
expect(
1957+
tester.getRect(find.byType(Switch).at(0)),
1958+
const Rect.fromLTWH(800.0 - 60.0 - 24.0, 8.0, 60.0, 40.0),
1959+
);
1960+
expect(
1961+
tester.getRect(find.byType(SwitchListTile).at(1)),
1962+
const Rect.fromLTWH(0.0, height, 800.0, 88.0),
1963+
);
1964+
expect(
1965+
tester.getRect(find.byType(Switch).at(1)),
1966+
const Rect.fromLTWH(800.0 - 60.0 - 24.0, height + 8.0, 60.0, 40.0),
1967+
);
1968+
}
1969+
1970+
await tester.pumpWidget(buildFrame());
1971+
expectTwoLine();
1972+
1973+
await tester.pumpWidget(buildFrame(themeDataIsThreeLine: true));
1974+
expectThreeLine();
1975+
1976+
await tester.pumpWidget(buildFrame(themeDataIsThreeLine: false, themeIsThreeLine: true));
1977+
expectThreeLine();
1978+
1979+
await tester.pumpWidget(buildFrame(themeDataIsThreeLine: true, themeIsThreeLine: false));
1980+
expectTwoLine();
1981+
1982+
await tester.pumpWidget(buildFrame(isThreeLine: true));
1983+
expectThreeLine();
1984+
1985+
await tester.pumpWidget(buildFrame(themeIsThreeLine: true, isThreeLine: false));
1986+
expectTwoLine();
1987+
1988+
await tester.pumpWidget(buildFrame(themeDataIsThreeLine: true, isThreeLine: false));
1989+
expectTwoLine();
1990+
1991+
await tester.pumpWidget(
1992+
buildFrame(themeDataIsThreeLine: true, themeIsThreeLine: true, isThreeLine: false),
1993+
);
1994+
expectTwoLine();
1995+
1996+
await tester.pumpWidget(buildFrame(themeIsThreeLine: false, isThreeLine: true));
1997+
expectThreeLine();
1998+
1999+
await tester.pumpWidget(buildFrame(themeDataIsThreeLine: false, isThreeLine: true));
2000+
expectThreeLine();
2001+
2002+
await tester.pumpWidget(
2003+
buildFrame(themeDataIsThreeLine: false, themeIsThreeLine: false, isThreeLine: true),
2004+
);
2005+
expectThreeLine();
2006+
});
2007+
2008+
testWidgets('SwitchListTile.adaptive isThreeLine', (WidgetTester tester) async {
2009+
const double height = 300;
2010+
const double switchTop = 130.0;
2011+
2012+
Widget buildFrame({bool? themeDataIsThreeLine, bool? themeIsThreeLine, bool? isThreeLine}) {
2013+
return MaterialApp(
2014+
key: UniqueKey(),
2015+
theme: ThemeData(
2016+
platform: TargetPlatform.iOS,
2017+
listTileTheme:
2018+
themeDataIsThreeLine != null
2019+
? ListTileThemeData(isThreeLine: themeDataIsThreeLine)
2020+
: null,
2021+
),
2022+
home: Material(
2023+
child: ListTileTheme(
2024+
data:
2025+
themeIsThreeLine != null ? ListTileThemeData(isThreeLine: themeIsThreeLine) : null,
2026+
child: ListView(
2027+
children: <Widget>[
2028+
SwitchListTile.adaptive(
2029+
isThreeLine: isThreeLine,
2030+
title: const Text('A'),
2031+
subtitle: const Text('A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM'),
2032+
value: false,
2033+
onChanged: null,
2034+
),
2035+
SwitchListTile.adaptive(
2036+
isThreeLine: isThreeLine,
2037+
title: const Text('A'),
2038+
subtitle: const Text('A'),
2039+
value: false,
2040+
onChanged: null,
2041+
),
2042+
],
2043+
),
2044+
),
2045+
),
2046+
);
2047+
}
2048+
2049+
void expectTwoLine() {
2050+
expect(
2051+
tester.getRect(find.byType(SwitchListTile).at(0)),
2052+
const Rect.fromLTWH(0.0, 0.0, 800.0, height),
2053+
);
2054+
expect(
2055+
tester.getRect(find.byType(Switch).at(0)),
2056+
const Rect.fromLTWH(800.0 - 60.0 - 24.0, switchTop, 60.0, 40.0),
2057+
);
2058+
expect(
2059+
tester.getRect(find.byType(SwitchListTile).at(1)),
2060+
const Rect.fromLTWH(0.0, height, 800.0, 72.0),
2061+
);
2062+
expect(
2063+
tester.getRect(find.byType(Switch).at(1)),
2064+
const Rect.fromLTWH(800.0 - 60.0 - 24.0, height + 16, 60.0, 40.0),
2065+
);
2066+
}
2067+
2068+
void expectThreeLine() {
2069+
expect(
2070+
tester.getRect(find.byType(SwitchListTile).at(0)),
2071+
const Rect.fromLTWH(0.0, 0.0, 800.0, height),
2072+
);
2073+
expect(
2074+
tester.getRect(find.byType(Switch).at(0)),
2075+
const Rect.fromLTWH(800.0 - 60.0 - 24.0, 8.0, 60.0, 40.0),
2076+
);
2077+
expect(
2078+
tester.getRect(find.byType(SwitchListTile).at(1)),
2079+
const Rect.fromLTWH(0.0, height, 800.0, 88.0),
2080+
);
2081+
expect(
2082+
tester.getRect(find.byType(Switch).at(1)),
2083+
const Rect.fromLTWH(800.0 - 60.0 - 24.0, height + 8.0, 60.0, 40.0),
2084+
);
2085+
}
2086+
2087+
await tester.pumpWidget(buildFrame());
2088+
expectTwoLine();
2089+
2090+
await tester.pumpWidget(buildFrame(themeDataIsThreeLine: true));
2091+
expectThreeLine();
2092+
2093+
await tester.pumpWidget(buildFrame(themeDataIsThreeLine: false, themeIsThreeLine: true));
2094+
expectThreeLine();
2095+
2096+
await tester.pumpWidget(buildFrame(themeDataIsThreeLine: true, themeIsThreeLine: false));
2097+
expectTwoLine();
2098+
2099+
await tester.pumpWidget(buildFrame(isThreeLine: true));
2100+
expectThreeLine();
2101+
2102+
await tester.pumpWidget(buildFrame(themeIsThreeLine: true, isThreeLine: false));
2103+
expectTwoLine();
2104+
2105+
await tester.pumpWidget(buildFrame(themeDataIsThreeLine: true, isThreeLine: false));
2106+
expectTwoLine();
2107+
2108+
await tester.pumpWidget(
2109+
buildFrame(themeDataIsThreeLine: true, themeIsThreeLine: true, isThreeLine: false),
2110+
);
2111+
expectTwoLine();
2112+
2113+
await tester.pumpWidget(buildFrame(themeIsThreeLine: false, isThreeLine: true));
2114+
expectThreeLine();
2115+
2116+
await tester.pumpWidget(buildFrame(themeDataIsThreeLine: false, isThreeLine: true));
2117+
expectThreeLine();
2118+
2119+
await tester.pumpWidget(
2120+
buildFrame(themeDataIsThreeLine: false, themeIsThreeLine: false, isThreeLine: true),
2121+
);
2122+
expectThreeLine();
2123+
});
2124+
18942125
testWidgets('Material3 - SwitchListTile activeThumbColor', (WidgetTester tester) async {
18952126
await tester.pumpWidget(
18962127
Directionality(

0 commit comments

Comments
 (0)