Unverified Commit 8cb26651 authored by Playhi's avatar Playhi Committed by GitHub

Allow modification of ListTile's horizontalTitleGap, minVerticalPadding, minLeadingWidth (#64222)

Allow modification of ListTile's horizontalTitleGap, minVerticalPadding, minLeadingWidth
parent 6e3ebc93
......@@ -719,11 +719,17 @@ class ListTile extends StatelessWidget {
this.tileColor,
this.selectedTileColor,
this.enableFeedback,
this.horizontalTitleGap = 16.0,
this.minVerticalPadding = 4.0,
this.minLeadingWidth = 40.0,
}) : assert(isThreeLine != null),
assert(enabled != null),
assert(selected != null),
assert(autofocus != null),
assert(!isThreeLine || subtitle != null),
assert(horizontalTitleGap != null),
assert(minVerticalPadding != null),
assert(minLeadingWidth != null),
super(key: key);
/// A widget to display before the title.
......@@ -922,6 +928,15 @@ class ListTile extends StatelessWidget {
/// * [Feedback] for providing platform-specific feedback to certain actions.
final bool? enableFeedback;
/// The horizontal gap between the titles and the leading/trailing widgets.
final double horizontalTitleGap;
/// The minimum padding on the top and bottom of the title and subtitle widgets.
final double minVerticalPadding;
/// The minimum leading width.
final double minLeadingWidth;
/// Add a one pixel border in between each tile. If color isn't specified the
/// [ThemeData.dividerColor] of the context's [Theme] is used.
///
......@@ -1133,6 +1148,9 @@ class ListTile extends StatelessWidget {
textDirection: textDirection,
titleBaselineType: titleStyle.textBaseline!,
subtitleBaselineType: subtitleStyle?.textBaseline,
horizontalTitleGap: horizontalTitleGap,
minVerticalPadding: minVerticalPadding,
minLeadingWidth: minLeadingWidth,
),
),
),
......@@ -1161,12 +1179,18 @@ class _ListTile extends RenderObjectWidget {
required this.visualDensity,
required this.textDirection,
required this.titleBaselineType,
required this.horizontalTitleGap,
required this.minVerticalPadding,
required this.minLeadingWidth,
this.subtitleBaselineType,
}) : assert(isThreeLine != null),
assert(isDense != null),
assert(visualDensity != null),
assert(textDirection != null),
assert(titleBaselineType != null),
assert(horizontalTitleGap != null),
assert(minVerticalPadding != null),
assert(minLeadingWidth != null),
super(key: key);
final Widget? leading;
......@@ -1179,6 +1203,9 @@ class _ListTile extends RenderObjectWidget {
final TextDirection textDirection;
final TextBaseline titleBaselineType;
final TextBaseline? subtitleBaselineType;
final double horizontalTitleGap;
final double minVerticalPadding;
final double minLeadingWidth;
@override
_ListTileElement createElement() => _ListTileElement(this);
......@@ -1192,6 +1219,9 @@ class _ListTile extends RenderObjectWidget {
textDirection: textDirection,
titleBaselineType: titleBaselineType,
subtitleBaselineType: subtitleBaselineType,
horizontalTitleGap: horizontalTitleGap,
minVerticalPadding: minVerticalPadding,
minLeadingWidth: minLeadingWidth,
);
}
......@@ -1203,7 +1233,10 @@ class _ListTile extends RenderObjectWidget {
..visualDensity = visualDensity
..textDirection = textDirection
..titleBaselineType = titleBaselineType
..subtitleBaselineType = subtitleBaselineType;
..subtitleBaselineType = subtitleBaselineType
..horizontalTitleGap = horizontalTitleGap
..minLeadingWidth = minLeadingWidth
..minVerticalPadding = minVerticalPadding;
}
}
......@@ -1319,23 +1352,26 @@ class _RenderListTile extends RenderBox {
required TextDirection textDirection,
required TextBaseline titleBaselineType,
TextBaseline? subtitleBaselineType,
required double horizontalTitleGap,
required double minVerticalPadding,
required double minLeadingWidth,
}) : assert(isDense != null),
assert(visualDensity != null),
assert(isThreeLine != null),
assert(textDirection != null),
assert(titleBaselineType != null),
assert(horizontalTitleGap != null),
assert(minVerticalPadding != null),
assert(minLeadingWidth != null),
_isDense = isDense,
_visualDensity = visualDensity,
_isThreeLine = isThreeLine,
_textDirection = textDirection,
_titleBaselineType = titleBaselineType,
_subtitleBaselineType = subtitleBaselineType;
static const double _minLeadingWidth = 40.0;
// The horizontal gap between the titles and the leading/trailing widgets
double get _horizontalTitleGap => 16.0 + visualDensity.horizontal * 2.0;
// The minimum padding on the top and bottom of the title and subtitle widgets.
static const double _minVerticalPadding = 4.0;
_subtitleBaselineType = subtitleBaselineType,
_horizontalTitleGap = horizontalTitleGap + visualDensity.horizontal * 2.0,
_minVerticalPadding = minVerticalPadding,
_minLeadingWidth = minLeadingWidth;
final Map<_ListTileSlot, RenderBox> children = <_ListTileSlot, RenderBox>{};
......@@ -1446,6 +1482,39 @@ class _RenderListTile extends RenderBox {
markNeedsLayout();
}
double get horizontalTitleGap => _horizontalTitleGap;
double _horizontalTitleGap;
set horizontalTitleGap(double value) {
assert(value != null);
if (_horizontalTitleGap == value)
return;
_horizontalTitleGap = value;
markNeedsLayout();
}
double get minVerticalPadding => _minVerticalPadding;
double _minVerticalPadding;
set minVerticalPadding(double value) {
assert(value != null);
if (_minVerticalPadding == value)
return;
_minVerticalPadding = value;
markNeedsLayout();
}
double get minLeadingWidth => _minLeadingWidth;
double _minLeadingWidth;
set minLeadingWidth(double value) {
assert(value != null);
if (_minLeadingWidth == value)
return;
_minLeadingWidth = value;
markNeedsLayout();
}
@override
void attach(PipelineOwner owner) {
super.attach(owner);
......
......@@ -1834,4 +1834,161 @@ void main() {
expect(feedback.hapticCount, 0);
});
});
testWidgets('ListTile horizontalTitleGap = 0.0', (WidgetTester tester) async {
Widget buildFrame(TextDirection textDirection) {
return MediaQuery(
data: const MediaQueryData(
padding: EdgeInsets.zero,
textScaleFactor: 1.0,
),
child: Directionality(
textDirection: textDirection,
child: Material(
child: Container(
alignment: Alignment.topLeft,
child: const ListTile(
horizontalTitleGap: 0.0,
leading: Text('L'),
title: Text('title'),
trailing: Text('T'),
),
),
),
),
);
}
double left(String text) => tester.getTopLeft(find.text(text)).dx;
double right(String text) => tester.getTopRight(find.text(text)).dx;
await tester.pumpWidget(buildFrame(TextDirection.ltr));
expect(tester.getSize(find.byType(ListTile)), const Size(800.0, 56.0));
expect(left('title'), 56.0); // horizontalTitleGap: 0
await tester.pumpWidget(buildFrame(TextDirection.rtl));
expect(tester.getSize(find.byType(ListTile)), const Size(800.0, 56.0));
expect(right('title'), 744.0); // horizontalTitleGap: 0
});
testWidgets('ListTile horizontalTitleGap = (default) && ListTile minLeadingWidth = (default)', (WidgetTester tester) async {
Widget buildFrame(TextDirection textDirection) {
return MediaQuery(
data: const MediaQueryData(
padding: EdgeInsets.zero,
textScaleFactor: 1.0,
),
child: Directionality(
textDirection: textDirection,
child: Material(
child: Container(
alignment: Alignment.topLeft,
child: const ListTile(
leading: Text('L'),
title: Text('title'),
trailing: Text('T'),
),
),
),
),
);
}
double left(String text) => tester.getTopLeft(find.text(text)).dx;
double right(String text) => tester.getTopRight(find.text(text)).dx;
await tester.pumpWidget(buildFrame(TextDirection.ltr));
expect(tester.getSize(find.byType(ListTile)), const Size(800.0, 56.0));
// horizontalTitleGap: ListTileDefaultValue.horizontalTitleGap (16.0)
expect(left('title'), 72.0);
await tester.pumpWidget(buildFrame(TextDirection.rtl));
expect(tester.getSize(find.byType(ListTile)), const Size(800.0, 56.0));
// horizontalTitleGap: ListTileDefaultValue.horizontalTitleGap (16.0)
expect(right('title'), 728.0);
});
testWidgets('ListTile minVerticalPadding = 80.0', (WidgetTester tester) async {
Widget buildFrame(TextDirection textDirection) {
return MediaQuery(
data: const MediaQueryData(
padding: EdgeInsets.zero,
textScaleFactor: 1.0,
),
child: Directionality(
textDirection: textDirection,
child: Material(
child: Container(
alignment: Alignment.topLeft,
child: const ListTile(
minVerticalPadding: 80.0,
leading: Text('L'),
title: Text('title'),
trailing: Text('T'),
),
),
),
),
);
}
await tester.pumpWidget(buildFrame(TextDirection.ltr));
// minVerticalPadding: 80.0
// 80 + 80 + 16(Title) = 176
expect(tester.getSize(find.byType(ListTile)), const Size(800.0, 176.0));
await tester.pumpWidget(buildFrame(TextDirection.rtl));
// minVerticalPadding: 80.0
// 80 + 80 + 16(Title) = 176
expect(tester.getSize(find.byType(ListTile)), const Size(800.0, 176.0));
});
testWidgets('ListTile minLeadingWidth = 60.0', (WidgetTester tester) async {
Widget buildFrame(TextDirection textDirection) {
return MediaQuery(
data: const MediaQueryData(
padding: EdgeInsets.zero,
textScaleFactor: 1.0,
),
child: Directionality(
textDirection: textDirection,
child: Material(
child: Container(
alignment: Alignment.topLeft,
child: const ListTile(
minLeadingWidth: 60.0,
leading: Text('L'),
title: Text('title'),
trailing: Text('T'),
),
),
),
),
);
}
double left(String text) => tester.getTopLeft(find.text(text)).dx;
double right(String text) => tester.getTopRight(find.text(text)).dx;
await tester.pumpWidget(buildFrame(TextDirection.ltr));
expect(tester.getSize(find.byType(ListTile)), const Size(800.0, 56.0));
// minLeadingWidth: 60.0
// 92.0 = 16.0(Default contentPadding) + 16.0(Default horizontalTitleGap) + 60.0
expect(left('title'), 92.0);
await tester.pumpWidget(buildFrame(TextDirection.rtl));
expect(tester.getSize(find.byType(ListTile)), const Size(800.0, 56.0));
// minLeadingWidth: 60.0
// 708.0 = 800.0 - (16.0(Default contentPadding) + 16.0(Default horizontalTitleGap) + 60.0)
expect(right('title'), 708.0);
});
}
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