diff --git a/packages/flutter/lib/src/material/switch_list_tile.dart b/packages/flutter/lib/src/material/switch_list_tile.dart index f3b6a7fd1fa..fdec3ec6d64 100644 --- a/packages/flutter/lib/src/material/switch_list_tile.dart +++ b/packages/flutter/lib/src/material/switch_list_tile.dart @@ -13,6 +13,8 @@ import 'theme_data.dart'; // void setState(VoidCallback fn) { } // bool _lights; +enum _SwitchListTileType { material, adaptive } + /// A [ListTile] with a [Switch]. In other words, a switch with a label. /// /// The entire list tile is interactive: tapping anywhere in the tile toggles @@ -90,7 +92,39 @@ class SwitchListTile extends StatelessWidget { this.dense, this.secondary, this.selected = false, - }) : assert(value != null), + }) : _switchListTileType = _SwitchListTileType.material, + assert(value != null), + assert(isThreeLine != null), + assert(!isThreeLine || subtitle != null), + assert(selected != null), + super(key: key); + + /// Creates the wrapped switch with [Switch.adaptive]. + /// + /// Creates a [CupertinoSwitch] if the target platform is iOS, creates a + /// material design switch otherwise. + /// + /// If a [CupertinoSwitch] is created, the following parameters are + /// ignored: [activeTrackColor], [inactiveThumbColor], [inactiveTrackColor], + /// [activeThumbImage], [inactiveThumbImage], [materialTapTargetSize]. + const SwitchListTile.adaptive({ + Key key, + @required this.value, + @required this.onChanged, + this.activeColor, + this.activeTrackColor, + this.inactiveThumbColor, + this.inactiveTrackColor, + this.activeThumbImage, + this.inactiveThumbImage, + this.title, + this.subtitle, + this.isThreeLine = false, + this.dense, + this.secondary, + this.selected = false, + }) : _switchListTileType = _SwitchListTileType.adaptive, + assert(value != null), assert(isThreeLine != null), assert(!isThreeLine || subtitle != null), assert(selected != null), @@ -134,22 +168,30 @@ class SwitchListTile extends StatelessWidget { /// The color to use on the track when this switch is on. /// /// Defaults to [ThemeData.toggleableActiveColor] with the opacity set at 50%. + /// + /// Ignored if created with [SwitchListTile.adaptive]. final Color activeTrackColor; /// The color to use on the thumb when this switch is off. /// /// Defaults to the colors described in the Material design specification. + /// + /// Ignored if created with [SwitchListTile.adaptive]. final Color inactiveThumbColor; /// The color to use on the track when this switch is off. /// /// Defaults to the colors described in the Material design specification. + /// + /// Ignored if created with [SwitchListTile.adaptive]. final Color inactiveTrackColor; /// An image to use on the thumb of this switch when the switch is on. final ImageProvider activeThumbImage; /// An image to use on the thumb of this switch when the switch is off. + /// + /// Ignored if created with [SwitchListTile.adaptive]. final ImageProvider inactiveThumbImage; /// The primary content of the list tile. @@ -187,19 +229,40 @@ class SwitchListTile extends StatelessWidget { /// Normally, this property is left to its default value, false. final bool selected; + /// If adaptive, creates the switch with [Switch.adaptive]. + final _SwitchListTileType _switchListTileType; + @override Widget build(BuildContext context) { - final Widget control = Switch( - value: value, - onChanged: onChanged, - activeColor: activeColor, - activeThumbImage: activeThumbImage, - inactiveThumbImage: inactiveThumbImage, - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - activeTrackColor: activeTrackColor, - inactiveTrackColor: inactiveTrackColor, - inactiveThumbColor: inactiveThumbColor, - ); + Widget control; + switch (_switchListTileType) { + case _SwitchListTileType.adaptive: + control = Switch.adaptive( + value: value, + onChanged: onChanged, + activeColor: activeColor, + activeThumbImage: activeThumbImage, + inactiveThumbImage: inactiveThumbImage, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + activeTrackColor: activeTrackColor, + inactiveTrackColor: inactiveTrackColor, + inactiveThumbColor: inactiveThumbColor, + ); + break; + + case _SwitchListTileType.material: + control = Switch( + value: value, + onChanged: onChanged, + activeColor: activeColor, + activeThumbImage: activeThumbImage, + inactiveThumbImage: inactiveThumbImage, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + activeTrackColor: activeTrackColor, + inactiveTrackColor: inactiveTrackColor, + inactiveThumbColor: inactiveThumbColor, + ); + } return MergeSemantics( child: ListTileTheme.merge( selectedColor: activeColor ?? Theme.of(context).accentColor, diff --git a/packages/flutter/test/material/switch_list_tile_test.dart b/packages/flutter/test/material/switch_list_tile_test.dart index 1a019dba08b..a4ce394d321 100644 --- a/packages/flutter/test/material/switch_list_tile_test.dart +++ b/packages/flutter/test/material/switch_list_tile_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; @@ -58,4 +59,45 @@ void main() { ..circle(color: Colors.red[500]) ); }); + + testWidgets('SwitchListTile.adaptive delegates to', (WidgetTester tester) async { + bool value = false; + + Widget buildFrame(TargetPlatform platform) { + return MaterialApp( + theme: ThemeData(platform: platform), + home: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Material( + child: Center( + child: SwitchListTile.adaptive( + value: value, + onChanged: (bool newValue) { + setState(() { + value = newValue; + }); + }, + ), + ), + ); + }, + ), + ); + } + + await tester.pumpWidget(buildFrame(TargetPlatform.iOS)); + expect(find.byType(CupertinoSwitch), findsOneWidget); + expect(value, isFalse); + + await tester.tap(find.byType(SwitchListTile)); + expect(value, isTrue); + + await tester.pumpWidget(buildFrame(TargetPlatform.android)); + await tester.pumpAndSettle(); // Finish the theme change animation. + + expect(find.byType(CupertinoSwitch), findsNothing); + expect(value, isTrue); + await tester.tap(find.byType(SwitchListTile)); + expect(value, isFalse); + }); }