Unverified Commit 567db6f0 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Improved positioning of leading and trailing widgets in overflowing ListTiles (#24767)

parent 07e06171
...@@ -160,10 +160,9 @@ enum ListTileControlAffinity { ...@@ -160,10 +160,9 @@ enum ListTileControlAffinity {
/// is true then the overall height of this tile and the size of the /// is true then the overall height of this tile and the size of the
/// [DefaultTextStyle]s that wrap the [title] and [subtitle] widget are reduced. /// [DefaultTextStyle]s that wrap the [title] and [subtitle] widget are reduced.
/// ///
/// List tiles are always a fixed height (which height depends on how /// It is the responsibility of the caller to ensure that [title] does not wrap,
/// [isThreeLine], [dense], and [subtitle] are configured); they do not grow in /// and to ensure that [subtitle] doesn't wrap (if [isThreeLine] is false) or
/// height based on their contents. If you are looking for a widget that allows /// wraps to two lines (if it is true).
/// for arbitrary layout in a row, consider [Row].
/// ///
/// List tiles are typically used in [ListView]s, or arranged in [Column]s in /// List tiles are typically used in [ListView]s, or arranged in [Column]s in
/// [Drawer]s and [Card]s. /// [Drawer]s and [Card]s.
...@@ -246,20 +245,36 @@ class ListTile extends StatelessWidget { ...@@ -246,20 +245,36 @@ class ListTile extends StatelessWidget {
/// The primary content of the list tile. /// The primary content of the list tile.
/// ///
/// Typically a [Text] widget. /// Typically a [Text] widget.
///
/// This should not wrap.
final Widget title; final Widget title;
/// Additional content displayed below the title. /// Additional content displayed below the title.
/// ///
/// Typically a [Text] widget. /// Typically a [Text] widget.
///
/// If [isThreeLine] is false, this should not wrap.
///
/// If [isThreeLine] is true, this should be configured to take a maximum of
/// two lines.
final Widget subtitle; final Widget subtitle;
/// A widget to display after the title. /// A widget to display after the title.
/// ///
/// Typically an [Icon] widget. /// Typically an [Icon] widget.
///
/// To show right-aligned metadata (assuming left-to-right reading order;
/// left-aligned for right-to-left reading order), consider using a [Row] with
/// [MainAxisAlign.baseline] alignment whose first item is [Expanded] and
/// whose second child is the metadata text, instead of using the [trailing]
/// property.
final Widget trailing; final Widget trailing;
/// Whether this list tile is intended to display three lines of text. /// Whether this list tile is intended to display three lines of text.
/// ///
/// If true, then [subtitle] must be non-null (since it is expected to give
/// the second and third lines of text).
///
/// If false, the list tile is treated as having one line if the subtitle is /// 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. /// null and treated as having two lines if the subtitle is non-null.
final bool isThreeLine; final bool isThreeLine;
...@@ -267,6 +282,8 @@ class ListTile extends StatelessWidget { ...@@ -267,6 +282,8 @@ class ListTile extends StatelessWidget {
/// Whether this list tile is part of a vertically dense list. /// Whether this list tile is part of a vertically dense list.
/// ///
/// If this property is null then its value is based on [ListTileTheme.dense]. /// If this property is null then its value is based on [ListTileTheme.dense].
///
/// Dense list tiles default to a smaller height.
final bool dense; final bool dense;
/// The tile's internal padding. /// The tile's internal padding.
...@@ -934,17 +951,19 @@ class _RenderListTile extends RenderBox { ...@@ -934,17 +951,19 @@ class _RenderListTile extends RenderBox {
assert(isOneLine); assert(isOneLine);
} }
final double defaultTileHeight = _defaultTileHeight;
double tileHeight; double tileHeight;
double titleY; double titleY;
double subtitleY; double subtitleY;
if (!hasSubtitle) { if (!hasSubtitle) {
tileHeight = math.max(_defaultTileHeight, titleSize.height + 2.0 * _minVerticalPadding); tileHeight = math.max(defaultTileHeight, titleSize.height + 2.0 * _minVerticalPadding);
titleY = (tileHeight - titleSize.height) / 2.0; titleY = (tileHeight - titleSize.height) / 2.0;
} else { } else {
assert(subtitleBaselineType != null); assert(subtitleBaselineType != null);
titleY = titleBaseline - _boxBaseline(title, titleBaselineType); titleY = titleBaseline - _boxBaseline(title, titleBaselineType);
subtitleY = subtitleBaseline - _boxBaseline(subtitle, subtitleBaselineType); subtitleY = subtitleBaseline - _boxBaseline(subtitle, subtitleBaselineType);
tileHeight = _defaultTileHeight; tileHeight = defaultTileHeight;
// If the title and subtitle overlap, move the title upwards by half // If the title and subtitle overlap, move the title upwards by half
// the overlap and the subtitle down by the same amount, and adjust // the overlap and the subtitle down by the same amount, and adjust
...@@ -966,8 +985,30 @@ class _RenderListTile extends RenderBox { ...@@ -966,8 +985,30 @@ class _RenderListTile extends RenderBox {
} }
} }
final double leadingY = (tileHeight - leadingSize.height) / 2.0; // This attempts to implement the redlines for the vertical position of the
final double trailingY = (tileHeight - trailingSize.height) / 2.0; // leading and trailing icons on the spec page:
// https://material.io/design/components/lists.html#specs
// Some liberties have been taken to handle cases that aren't covered by
// that specification, such as leading and trailing widgets with weird
// sizes, "one-line" list tiles with title widgets that span multiple lines,
// etc.
double leadingY;
double trailingY;
if (isOneLine) {
leadingY = (defaultTileHeight - leadingSize.height) / 2.0;
trailingY = (defaultTileHeight - trailingSize.height) / 2.0;
} else if (isTwoLine) {
if (isDense) {
leadingY = 12.0; // by extrapolation
trailingY = 20.0; // by extrapolation
} else {
leadingY = leadingSize.height <= 40.0 ? 16.0 : 8.0;
trailingY = 24.0;
}
} else {
leadingY = 16.0;
trailingY = 16.0;
}
switch (textDirection) { switch (textDirection) {
case TextDirection.rtl: { case TextDirection.rtl: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment