Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
0e2eeb5a
Unverified
Commit
0e2eeb5a
authored
Mar 29, 2019
by
Shi-Hao Hong
Committed by
GitHub
Mar 29, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Set Max Height for ListTile trailing and leading widgets (#29771)
parent
ffbb335e
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
391 additions
and
2 deletions
+391
-2
list_tile.dart
packages/flutter/lib/src/material/list_tile.dart
+57
-2
list_tile_test.dart
packages/flutter/test/material/list_tile_test.dart
+334
-0
No files found.
packages/flutter/lib/src/material/list_tile.dart
View file @
0e2eeb5a
...
@@ -164,6 +164,13 @@ enum ListTileControlAffinity {
...
@@ -164,6 +164,13 @@ enum ListTileControlAffinity {
/// and to ensure that [subtitle] doesn't wrap (if [isThreeLine] is false) or
/// and to ensure that [subtitle] doesn't wrap (if [isThreeLine] is false) or
/// wraps to two lines (if it is true).
/// wraps to two lines (if it is true).
///
///
/// The heights of the [leading] and [trailing] widgets are constrained
/// according to the [Material spec]
/// (https://material.io/design/components/lists.html).
/// An exception is made for one-line ListTiles for accessibility. Please
/// see the example below to see how to adhere to both Material spec and
/// accessibility requirements.
///
/// 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.
///
///
...
@@ -199,6 +206,44 @@ enum ListTileControlAffinity {
...
@@ -199,6 +206,44 @@ enum ListTileControlAffinity {
/// ```
/// ```
/// {@end-tool}
/// {@end-tool}
///
///
/// To be accessible, tappable [leading] and [trailing] widgets have to
/// be at least 48x48 in size. However, to adhere to the Material spec,
/// [trailing] and [leading] widgets in one-line ListTiles should visually be
/// at most 32 ([dense]: true) or 40 ([dense]: false) in height, which may
/// conflict with the accessibility requirement.
///
/// For this reason, a one-line ListTile allows the height of [leading]
/// and [trailing] widgets to be constrained by the height of the ListTile.
/// This allows for the creation of tappable [leading] and [trailing] widgets
/// that are large enough, but it is up to the developer to ensure that
/// their widgets follow the Material spec.
///
/// The following is an example of a one-line, non-[dense] ListTile with a
/// tappable leading widget that adheres to accessibility requirements and
/// the Material spec. To adjust the use case below for a one-line, [dense]
/// ListTile, adjust the vertical padding to 8.0.
///
/// {@tool sample}
///
/// ```dart
/// ListTile(
/// leading: GestureDetector(
/// behavior: HitTestBehavior.translucent,
/// onTap: () {},
/// child: Container(
/// width: 48,
/// height: 48,
/// padding: EdgeInsets.symmetric(vertical: 4.0),
/// alignment: Alignment.center,
/// child: CircleAvatar(),
/// ),
/// ),
/// title: Text('title'),
/// dense: false,
/// ),
/// ```
/// {@end-tool}
///
/// See also:
/// See also:
///
///
/// * [ListTileTheme], which defines visual properties for [ListTile]s.
/// * [ListTileTheme], which defines visual properties for [ListTile]s.
...
@@ -924,11 +969,21 @@ class _RenderListTile extends RenderBox {
...
@@ -924,11 +969,21 @@ class _RenderListTile extends RenderBox {
final
bool
hasTrailing
=
trailing
!=
null
;
final
bool
hasTrailing
=
trailing
!=
null
;
final
bool
isTwoLine
=
!
isThreeLine
&&
hasSubtitle
;
final
bool
isTwoLine
=
!
isThreeLine
&&
hasSubtitle
;
final
bool
isOneLine
=
!
isThreeLine
&&
!
hasSubtitle
;
final
bool
isOneLine
=
!
isThreeLine
&&
!
hasSubtitle
;
final
BoxConstraints
maxIconHeightConstraint
=
BoxConstraints
(
// One-line trailing and leading widget heights do not follow
// Material specifications, but this sizing is required to adhere
// to accessibility requirements for smallest tappable widget.
// Two- and three-line trailing widget heights are constrained
// properly according to the Material spec.
maxHeight:
isDense
?
48.0
:
56.0
,
);
final
BoxConstraints
looseConstraints
=
constraints
.
loosen
();
final
BoxConstraints
looseConstraints
=
constraints
.
loosen
();
final
BoxConstraints
iconConstraints
=
looseConstraints
.
enforce
(
maxIconHeightConstraint
);
final
double
tileWidth
=
looseConstraints
.
maxWidth
;
final
double
tileWidth
=
looseConstraints
.
maxWidth
;
final
Size
leadingSize
=
_layoutBox
(
leading
,
loose
Constraints
);
final
Size
leadingSize
=
_layoutBox
(
leading
,
icon
Constraints
);
final
Size
trailingSize
=
_layoutBox
(
trailing
,
loose
Constraints
);
final
Size
trailingSize
=
_layoutBox
(
trailing
,
icon
Constraints
);
final
double
titleStart
=
hasLeading
final
double
titleStart
=
hasLeading
?
math
.
max
(
_minLeadingWidth
,
leadingSize
.
width
)
+
_horizontalTitleGap
?
math
.
max
(
_minLeadingWidth
,
leadingSize
.
width
)
+
_horizontalTitleGap
...
...
packages/flutter/test/material/list_tile_test.dart
View file @
0e2eeb5a
...
@@ -785,4 +785,338 @@ void main() {
...
@@ -785,4 +785,338 @@ void main() {
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
2
)),
Rect
.
fromLTWH
(
16.0
,
216.0
+
16.0
,
24.0
,
12.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
2
)),
Rect
.
fromLTWH
(
16.0
,
216.0
+
16.0
,
24.0
,
12.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
3
)),
Rect
.
fromLTWH
(
800.0
-
24.0
-
16.0
,
216.0
+
16.0
,
24.0
,
24.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
3
)),
Rect
.
fromLTWH
(
800.0
-
24.0
-
16.0
,
216.0
+
16.0
,
24.0
,
24.0
));
});
});
testWidgets
(
'ListTile leading icon height does not exceed ListTile height'
,
(
WidgetTester
tester
)
async
{
// regression test for https://github.com/flutter/flutter/issues/28765
const
SizedBox
oversizedWidget
=
SizedBox
(
height:
80.0
,
width:
24.0
,
child:
Placeholder
());
// Dense One line
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ListTile
(
leading:
oversizedWidget
,
title:
Text
(
'A'
),
dense:
true
,
),
ListTile
(
leading:
oversizedWidget
,
title:
Text
(
'B'
),
dense:
true
,
),
],
),
),
),
);
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
0
)),
Rect
.
fromLTWH
(
16.0
,
0.0
,
24.0
,
48.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
1
)),
Rect
.
fromLTWH
(
16.0
,
48.0
,
24.0
,
48.0
));
// Non-dense One line
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ListTile
(
leading:
oversizedWidget
,
title:
Text
(
'A'
),
dense:
false
,
),
ListTile
(
leading:
oversizedWidget
,
title:
Text
(
'B'
),
dense:
false
,
),
],
),
),
),
);
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
0
)),
Rect
.
fromLTWH
(
16.0
,
0.0
,
24.0
,
56.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
1
)),
Rect
.
fromLTWH
(
16.0
,
56.0
,
24.0
,
56.0
));
// Dense Two line
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ListTile
(
leading:
oversizedWidget
,
title:
Text
(
'A'
),
subtitle:
Text
(
'A'
),
dense:
true
,
),
ListTile
(
leading:
oversizedWidget
,
title:
Text
(
'B'
),
subtitle:
Text
(
'B'
),
dense:
true
,
),
],
),
),
),
);
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
0
)),
Rect
.
fromLTWH
(
16.0
,
8.0
,
24.0
,
48.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
1
)),
Rect
.
fromLTWH
(
16.0
,
64.0
+
8.0
,
24.0
,
48.0
));
// Non-dense Two line
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ListTile
(
leading:
oversizedWidget
,
title:
Text
(
'A'
),
subtitle:
Text
(
'A'
),
dense:
false
,
),
ListTile
(
leading:
oversizedWidget
,
title:
Text
(
'B'
),
subtitle:
Text
(
'B'
),
dense:
false
,
),
],
),
),
),
);
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
0
)),
Rect
.
fromLTWH
(
16.0
,
8.0
,
24.0
,
56.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
1
)),
Rect
.
fromLTWH
(
16.0
,
72.0
+
8.0
,
24.0
,
56.0
));
// Dense Three line
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ListTile
(
leading:
oversizedWidget
,
title:
Text
(
'A'
),
subtitle:
Text
(
'A'
),
isThreeLine:
true
,
dense:
true
,
),
ListTile
(
leading:
oversizedWidget
,
title:
Text
(
'B'
),
subtitle:
Text
(
'B'
),
isThreeLine:
true
,
dense:
true
,
),
],
),
),
),
);
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
0
)),
Rect
.
fromLTWH
(
16.0
,
16.0
,
24.0
,
48.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
1
)),
Rect
.
fromLTWH
(
16.0
,
76.0
+
16.0
,
24.0
,
48.0
));
// Non-dense Three line
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ListTile
(
leading:
oversizedWidget
,
title:
Text
(
'A'
),
subtitle:
Text
(
'A'
),
isThreeLine:
true
,
dense:
false
,
),
ListTile
(
leading:
oversizedWidget
,
title:
Text
(
'B'
),
subtitle:
Text
(
'B'
),
isThreeLine:
true
,
dense:
false
,
),
],
),
),
),
);
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
0
)),
Rect
.
fromLTWH
(
16.0
,
16.0
,
24.0
,
56.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
1
)),
Rect
.
fromLTWH
(
16.0
,
88.0
+
16.0
,
24.0
,
56.0
));
});
testWidgets
(
'ListTile trailing icon height does not exceed ListTile height'
,
(
WidgetTester
tester
)
async
{
// regression test for https://github.com/flutter/flutter/issues/28765
const
SizedBox
oversizedWidget
=
SizedBox
(
height:
80.0
,
width:
24.0
,
child:
Placeholder
());
// Dense One line
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ListTile
(
trailing:
oversizedWidget
,
title:
Text
(
'A'
),
dense:
true
,
),
ListTile
(
trailing:
oversizedWidget
,
title:
Text
(
'B'
),
dense:
true
,
),
],
),
),
),
);
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
0
)),
Rect
.
fromLTWH
(
800.0
-
16.0
-
24.0
,
0
,
24.0
,
48.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
1
)),
Rect
.
fromLTWH
(
800.0
-
16.0
-
24.0
,
48.0
,
24.0
,
48.0
));
// Non-dense One line
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ListTile
(
trailing:
oversizedWidget
,
title:
Text
(
'A'
),
dense:
false
,
),
ListTile
(
trailing:
oversizedWidget
,
title:
Text
(
'B'
),
dense:
false
,
),
],
),
),
),
);
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
0
)),
Rect
.
fromLTWH
(
800.0
-
16.0
-
24.0
,
0.0
,
24.0
,
56.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
1
)),
Rect
.
fromLTWH
(
800.0
-
16.0
-
24.0
,
56.0
,
24.0
,
56.0
));
// Dense Two line
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ListTile
(
trailing:
oversizedWidget
,
title:
Text
(
'A'
),
subtitle:
Text
(
'A'
),
dense:
true
,
),
ListTile
(
trailing:
oversizedWidget
,
title:
Text
(
'B'
),
subtitle:
Text
(
'B'
),
dense:
true
,
),
],
),
),
),
);
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
0
)),
Rect
.
fromLTWH
(
800.0
-
16.0
-
24.0
,
8.0
,
24.0
,
48.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
1
)),
Rect
.
fromLTWH
(
800.0
-
16.0
-
24.0
,
64.0
+
8.0
,
24.0
,
48.0
));
// Non-dense Two line
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ListTile
(
trailing:
oversizedWidget
,
title:
Text
(
'A'
),
subtitle:
Text
(
'A'
),
dense:
false
,
),
ListTile
(
trailing:
oversizedWidget
,
title:
Text
(
'B'
),
subtitle:
Text
(
'B'
),
dense:
false
,
),
],
),
),
),
);
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
0
)),
Rect
.
fromLTWH
(
800.0
-
16.0
-
24.0
,
8.0
,
24.0
,
56.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
1
)),
Rect
.
fromLTWH
(
800.0
-
16.0
-
24.0
,
72.0
+
8.0
,
24.0
,
56.0
));
// Dense Three line
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ListTile
(
trailing:
oversizedWidget
,
title:
Text
(
'A'
),
subtitle:
Text
(
'A'
),
isThreeLine:
true
,
dense:
true
,
),
ListTile
(
trailing:
oversizedWidget
,
title:
Text
(
'B'
),
subtitle:
Text
(
'B'
),
isThreeLine:
true
,
dense:
true
,
),
],
),
),
),
);
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
0
)),
Rect
.
fromLTWH
(
800.0
-
16.0
-
24.0
,
16.0
,
24.0
,
48.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
1
)),
Rect
.
fromLTWH
(
800.0
-
16.0
-
24.0
,
76.0
+
16.0
,
24.0
,
48.0
));
// Non-dense Three line
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
ListView
(
children:
const
<
Widget
>[
ListTile
(
trailing:
oversizedWidget
,
title:
Text
(
'A'
),
subtitle:
Text
(
'A'
),
isThreeLine:
true
,
dense:
false
,
),
ListTile
(
trailing:
oversizedWidget
,
title:
Text
(
'B'
),
subtitle:
Text
(
'B'
),
isThreeLine:
true
,
dense:
false
,
),
],
),
),
),
);
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
0
)),
Rect
.
fromLTWH
(
800.0
-
16.0
-
24.0
,
16.0
,
24.0
,
56.0
));
expect
(
tester
.
getRect
(
find
.
byType
(
Placeholder
).
at
(
1
)),
Rect
.
fromLTWH
(
800.0
-
16.0
-
24.0
,
88.0
+
16.0
,
24.0
,
56.0
));
});
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment