blob: 151234cba563d8bb7d14792387e1675f198f38d3 [file] [log] [blame]
// 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';
/// 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.
///
/// ## Sample code
///
/// This widget shows a switch that, when toggled, changes the state of a [bool]
/// member field called `_lights`.
///
/// ```dart
/// new SwitchListTile(
/// title: const Text('Lights'),
/// value: _lights,
/// onChanged: (bool value) { setState(() { _lights = value; }); },
/// secondary: const Icon(Icons.lightbulb_outline),
/// )
/// ```
///
/// 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.activeThumbImage,
this.inactiveThumbImage,
this.title,
this.subtitle,
this.isThreeLine = false,
this.dense,
this.secondary,
this.selected = false,
}) : 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
/// new SwitchListTile(
/// value: _lights,
/// onChanged: (bool newValue) {
/// setState(() {
/// _lights = newValue;
/// });
/// },
/// title: new 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;
/// 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.
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;
@override
Widget build(BuildContext context) {
final Widget control = new Switch(
value: value,
onChanged: onChanged,
activeColor: activeColor,
activeThumbImage: activeThumbImage,
inactiveThumbImage: inactiveThumbImage,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
);
return new MergeSemantics(
child: ListTileTheme.merge(
selectedColor: activeColor ?? Theme.of(context).accentColor,
child: new ListTile(
leading: secondary,
title: title,
subtitle: subtitle,
trailing: control,
isThreeLine: isThreeLine,
dense: dense,
enabled: onChanged != null,
onTap: onChanged != null ? () { onChanged(!value); } : null,
selected: selected,
),
),
);
}
}