// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/widgets.dart'; import 'list_tile.dart'; import 'switch.dart'; import 'theme.dart'; import 'theme_data.dart'; // Examples can assume: // 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 /// the switch. /// /// The [value], [onChanged], [activeColor], [activeThumbImage], and /// [inactiveThumbImage] properties of this widget are identical to the /// similarly-named properties on the [Switch] widget. /// /// The [title], [subtitle], [isThreeLine], and [dense] properties are like /// those of the same name on [ListTile]. /// /// The [selected] property on this widget is similar to the [ListTile.selected] /// property, but the color used is that described by [activeColor], if any, /// defaulting to the accent color of the current [Theme]. No effort is made to /// coordinate the [selected] state and the [value] state; to have the list tile /// 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]. /// /// To show the [SwitchListTile] as disabled, pass null as the [onChanged] /// callback. /// /// {@tool sample} /// /// This widget shows a switch that, when toggled, changes the state of a [bool] /// member field called `_lights`. /// /// ```dart /// SwitchListTile( /// title: const Text('Lights'), /// value: _lights, /// onChanged: (bool value) { setState(() { _lights = value; }); }, /// secondary: const Icon(Icons.lightbulb_outline), /// ) /// ``` /// {@end-tool} /// /// See also: /// /// * [ListTileTheme], which can be used to affect the style of list tiles, /// including switch list tiles. /// * [CheckboxListTile], a similar widget for checkboxes. /// * [RadioListTile], a similar widget for radio buttons. /// * [ListTile] and [Switch], the widgets from which this widget is made. class SwitchListTile extends StatelessWidget { /// Creates a combination of a list tile and a switch. /// /// The switch tile itself does not maintain any state. Instead, when the /// state of the switch changes, the widget calls the [onChanged] callback. /// Most widgets that use a switch will listen for the [onChanged] callback /// and rebuild the switch tile with a new [value] to update the visual /// appearance of the switch. /// /// The following arguments are required: /// /// * [value] determines whether this switch is on or off. /// * [onChanged] is called when the user toggles the switch on or off. const SwitchListTile({ 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.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), super(key: key); /// Whether this switch is checked. /// /// This property must not be null. final bool value; /// Called when the user toggles the switch on or off. /// /// The switch passes the new value to the callback but does not actually /// change state until the parent widget rebuilds the switch tile with the /// new value. /// /// If null, the switch will be displayed as disabled. /// /// The callback provided to [onChanged] should update the state of the parent /// [StatefulWidget] using the [State.setState] method, so that the parent /// gets rebuilt; for example: /// /// ```dart /// SwitchListTile( /// value: _lights, /// onChanged: (bool newValue) { /// setState(() { /// _lights = newValue; /// }); /// }, /// title: Text('Lights'), /// ) /// ``` final ValueChanged<bool> onChanged; /// The color to use when this switch is on. /// /// Defaults to accent color of the current [Theme]. final Color activeColor; /// 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. /// /// Typically a [Text] widget. final Widget title; /// Additional content displayed below the title. /// /// Typically a [Text] widget. final Widget subtitle; /// A widget to display on the opposite side of the tile from the switch. /// /// Typically an [Icon] widget. final Widget secondary; /// Whether this list tile is intended to display three lines of text. /// /// If false, the list tile is treated as having one line if the subtitle is /// null and treated as having two lines if the subtitle is non-null. final bool isThreeLine; /// Whether this list tile is part of a vertically dense list. /// /// If this property is null then its value is based on [ListTileTheme.dense]. final bool dense; /// Whether to render icons and text in the [activeColor]. /// /// No effort is made to automatically coordinate the [selected] state and the /// [value] state. To have the list tile appear selected when the switch is /// on, pass the same value to both. /// /// 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) { 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, child: ListTile( leading: secondary, title: title, subtitle: subtitle, trailing: control, isThreeLine: isThreeLine, dense: dense, enabled: onChanged != null, onTap: onChanged != null ? () { onChanged(!value); } : null, selected: selected, ), ), ); } }