[SwitchListTile] adds controlAffinity property (#58037)
diff --git a/AUTHORS b/AUTHORS
index a2cc16a..0e911ef 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -56,3 +56,4 @@
Katarina Sheremet <katarina@sheremet.ch>
Nicolas Schneider <nioncode+git@gmail.com>
Mikhail Zotyev <mbixjkee1392@gmail.com>
+Ayush Bherwani <ayush.bherwani1998@gmail.com>
diff --git a/packages/flutter/lib/src/material/list_tile.dart b/packages/flutter/lib/src/material/list_tile.dart
index 8be220e..a423a16 100644
--- a/packages/flutter/lib/src/material/list_tile.dart
+++ b/packages/flutter/lib/src/material/list_tile.dart
@@ -148,6 +148,7 @@
///
/// * [CheckboxListTile], which combines a [ListTile] with a [Checkbox].
/// * [RadioListTile], which combines a [ListTile] with a [Radio] button.
+/// * [SwitchListTile], which combines a [ListTile] with a [Switch].
enum ListTileControlAffinity {
/// Position the control on the leading edge, and the secondary widget, if
/// any, on the trailing edge.
diff --git a/packages/flutter/lib/src/material/switch_list_tile.dart b/packages/flutter/lib/src/material/switch_list_tile.dart
index 62fae85..cf14d89 100644
--- a/packages/flutter/lib/src/material/switch_list_tile.dart
+++ b/packages/flutter/lib/src/material/switch_list_tile.dart
@@ -39,9 +39,8 @@
/// appear selected when the switch is on, pass the same value to both.
///
/// The switch is shown on the right by default in left-to-right languages (i.e.
-/// in the [ListTile.trailing] slot). The [secondary] widget is placed in the
-/// [ListTile.leading] slot. This cannot be changed; there is not sufficient
-/// space in a [ListTile]'s [ListTile.leading] slot for a [Switch].
+/// in the [ListTile.trailing] slot) which can be changed using [controlAffinity].
+/// The [secondary] widget is placed in the [ListTile.leading] slot.
///
/// To show the [SwitchListTile] as disabled, pass null as the [onChanged]
/// callback.
@@ -273,6 +272,7 @@
this.secondary,
this.selected = false,
this.autofocus = false,
+ this.controlAffinity = ListTileControlAffinity.platform,
}) : _switchListTileType = _SwitchListTileType.material,
assert(value != null),
assert(isThreeLine != null),
@@ -307,6 +307,7 @@
this.secondary,
this.selected = false,
this.autofocus = false,
+ this.controlAffinity = ListTileControlAffinity.platform,
}) : _switchListTileType = _SwitchListTileType.adaptive,
assert(value != null),
assert(isThreeLine != null),
@@ -429,6 +430,11 @@
/// If adaptive, creates the switch with [Switch.adaptive].
final _SwitchListTileType _switchListTileType;
+ /// Defines the position of control and [secondary], relative to text.
+ ///
+ /// By default, the value of `controlAffinity` is [ListTileControlAffinity.platform].
+ final ListTileControlAffinity controlAffinity;
+
@override
Widget build(BuildContext context) {
Widget control;
@@ -462,14 +468,28 @@
autofocus: autofocus,
);
}
+
+ Widget leading, trailing;
+ switch (controlAffinity) {
+ case ListTileControlAffinity.leading:
+ leading = control;
+ trailing = secondary;
+ break;
+ case ListTileControlAffinity.trailing:
+ case ListTileControlAffinity.platform:
+ leading = secondary;
+ trailing = control;
+ break;
+ }
+
return MergeSemantics(
child: ListTileTheme.merge(
selectedColor: activeColor ?? Theme.of(context).accentColor,
child: ListTile(
- leading: secondary,
+ leading: leading,
title: title,
subtitle: subtitle,
- trailing: control,
+ trailing: trailing,
isThreeLine: isThreeLine,
dense: dense,
contentPadding: contentPadding,
diff --git a/packages/flutter/test/material/switch_list_tile_test.dart b/packages/flutter/test/material/switch_list_tile_test.dart
index a4ad456..a6bd56a 100644
--- a/packages/flutter/test/material/switch_list_tile_test.dart
+++ b/packages/flutter/test/material/switch_list_tile_test.dart
@@ -298,4 +298,44 @@
await tester.pump();
expect(Focus.of(childKey.currentContext, nullOk: true).hasPrimaryFocus, isFalse);
});
+
+ testWidgets('SwitchListTile controlAffinity test', (WidgetTester tester) async {
+ await tester.pumpWidget(const MaterialApp(
+ home: Material(
+ child: SwitchListTile(
+ value: true,
+ onChanged: null,
+ secondary: Icon(Icons.info),
+ title: Text('Title'),
+ controlAffinity: ListTileControlAffinity.leading,
+ ),
+ ),
+ ));
+
+ final ListTile listTile = tester.widget(find.byType(ListTile));
+ // When controlAffinity is ListTileControlAffinity.leading, the position of
+ // Switch is at leading edge and SwitchListTile.secondary at trailing edge.
+ expect(listTile.leading.runtimeType, Switch);
+ expect(listTile.trailing.runtimeType, Icon);
+ });
+
+ testWidgets('SwitchListTile controlAffinity default value test', (WidgetTester tester) async {
+ await tester.pumpWidget(const MaterialApp(
+ home: Material(
+ child: SwitchListTile(
+ value: true,
+ onChanged: null,
+ secondary: Icon(Icons.info),
+ title: Text('Title'),
+ ),
+ ),
+ ));
+
+ final ListTile listTile = tester.widget(find.byType(ListTile));
+ // By default, value of controlAffinity is ListTileControlAffinity.platform,
+ // where the position of SwitchListTile.secondary is at leading edge and Switch
+ // at trailing edge. This also covers test for ListTileControlAffinity.trailing.
+ expect(listTile.leading.runtimeType, Icon);
+ expect(listTile.trailing.runtimeType, Switch);
+ });
}