@@ -1234,6 +1234,291 @@ void main() {
1234
1234
expect (Focus .of (secondChildKey.currentContext! ).hasPrimaryFocus, isTrue);
1235
1235
});
1236
1236
1237
+ testWidgets ('CheckboxListTile minVerticalPadding = 80.0' , (WidgetTester tester) async {
1238
+ Widget buildFrame (TextDirection textDirection, { double ? themeMinVerticalPadding, double ? widgetMinVerticalPadding }) {
1239
+ return MaterialApp (
1240
+ theme: ThemeData (useMaterial3: true ),
1241
+ home: Directionality (
1242
+ textDirection: textDirection,
1243
+ child: Material (
1244
+ child: ListTileTheme (
1245
+ data: ListTileThemeData (minVerticalPadding: themeMinVerticalPadding),
1246
+ child: Container (
1247
+ alignment: Alignment .topLeft,
1248
+ child: CheckboxListTile (
1249
+ minVerticalPadding: widgetMinVerticalPadding,
1250
+ title: const Text ('title' ),
1251
+ value: false ,
1252
+ onChanged: (bool ? value) {},
1253
+ ),
1254
+ ),
1255
+ ),
1256
+ ),
1257
+ ),
1258
+ );
1259
+ }
1260
+
1261
+
1262
+ await tester.pumpWidget (buildFrame (TextDirection .ltr, widgetMinVerticalPadding: 80 ));
1263
+ // 80 + 80 + 16(Title) = 176
1264
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 184.0 ));
1265
+
1266
+ await tester.pumpWidget (buildFrame (TextDirection .ltr, themeMinVerticalPadding: 80 ));
1267
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 184.0 ));
1268
+
1269
+ await tester.pumpWidget (buildFrame (TextDirection .ltr, themeMinVerticalPadding: 0 , widgetMinVerticalPadding: 80 ));
1270
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 184.0 ));
1271
+
1272
+ await tester.pumpWidget (buildFrame (TextDirection .rtl, widgetMinVerticalPadding: 80 ));
1273
+ // 80 + 80 + 16(Title) = 176
1274
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 184.0 ));
1275
+
1276
+ await tester.pumpWidget (buildFrame (TextDirection .rtl, themeMinVerticalPadding: 80 ));
1277
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 184.0 ));
1278
+
1279
+ await tester.pumpWidget (buildFrame (TextDirection .rtl, themeMinVerticalPadding: 0 , widgetMinVerticalPadding: 80 ));
1280
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 184.0 ));
1281
+ });
1282
+
1283
+ testWidgets ('CheckboxListTile minLeadingWidth = 60.0' , (WidgetTester tester) async {
1284
+ Widget buildFrame (TextDirection textDirection, { double ? themeMinLeadingWidth, double ? widgetMinLeadingWidth }) {
1285
+ return MediaQuery (
1286
+ data: const MediaQueryData (),
1287
+ child: Directionality (
1288
+ textDirection: textDirection,
1289
+ child: Material (
1290
+ child: ListTileTheme (
1291
+ data: ListTileThemeData (minLeadingWidth: themeMinLeadingWidth),
1292
+ child: Container (
1293
+ alignment: Alignment .topLeft,
1294
+ child: CheckboxListTile (
1295
+ minLeadingWidth: widgetMinLeadingWidth,
1296
+ title: const Text ('title' ),
1297
+ value: false ,
1298
+ onChanged: (bool ? value) {},
1299
+ ),
1300
+ ),
1301
+ ),
1302
+ ),
1303
+ ),
1304
+ );
1305
+ }
1306
+
1307
+ double left (String text) => tester.getTopLeft (find.text (text)).dx;
1308
+ double right (String text) => tester.getTopRight (find.text (text)).dx;
1309
+
1310
+ await tester.pumpWidget (buildFrame (TextDirection .ltr, widgetMinLeadingWidth: 60 ));
1311
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1312
+ // 92.0 = 16.0(Default contentPadding) + 16.0(Default horizontalTitleGap) + 60.0
1313
+ expect (left ('title' ), 92.0 );
1314
+
1315
+ await tester.pumpWidget (buildFrame (TextDirection .ltr, themeMinLeadingWidth: 60 ));
1316
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1317
+ expect (left ('title' ), 92.0 );
1318
+
1319
+ await tester.pumpWidget (buildFrame (TextDirection .ltr, themeMinLeadingWidth: 0 , widgetMinLeadingWidth: 60 ));
1320
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1321
+ expect (left ('title' ), 92.0 );
1322
+
1323
+
1324
+ await tester.pumpWidget (buildFrame (TextDirection .rtl, widgetMinLeadingWidth: 60 ));
1325
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1326
+ // 708.0 = 800.0 - (16.0(Default contentPadding) + 16.0(Default horizontalTitleGap) + 60.0)
1327
+ expect (right ('title' ), 708.0 );
1328
+
1329
+ await tester.pumpWidget (buildFrame (TextDirection .rtl, themeMinLeadingWidth: 60 ));
1330
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1331
+ expect (right ('title' ), 708.0 );
1332
+
1333
+ await tester.pumpWidget (buildFrame (TextDirection .rtl, themeMinLeadingWidth: 0 , widgetMinLeadingWidth: 60 ));
1334
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1335
+ expect (right ('title' ), 708.0 );
1336
+ });
1337
+
1338
+ testWidgets ('CheckboxListTile minTileHeight' , (WidgetTester tester) async {
1339
+ Widget buildFrame (TextDirection textDirection, { double ? minTileHeight, }) {
1340
+ return MediaQuery (
1341
+ data: const MediaQueryData (),
1342
+ child: Directionality (
1343
+ textDirection: textDirection,
1344
+ child: Material (
1345
+ child: Container (
1346
+ alignment: Alignment .topLeft,
1347
+ child: CheckboxListTile (
1348
+ minTileHeight: minTileHeight,
1349
+ value: false ,
1350
+ onChanged: (bool ? value) {},
1351
+ ),
1352
+ ),
1353
+ ),
1354
+ ),
1355
+ );
1356
+ }
1357
+
1358
+ // Default list tile with height = 56.0
1359
+ await tester.pumpWidget (buildFrame (TextDirection .ltr));
1360
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1361
+
1362
+ // Set list tile height = 30.0
1363
+ await tester.pumpWidget (buildFrame (TextDirection .ltr, minTileHeight: 30 ));
1364
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 30.0 ));
1365
+
1366
+ // Set list tile height = 60.0
1367
+ await tester.pumpWidget (buildFrame (TextDirection .ltr, minTileHeight: 60 ));
1368
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 60.0 ));
1369
+ });
1370
+
1371
+ testWidgets ('CheckboxListTile titleAlignment position with title widget' , (WidgetTester tester) async {
1372
+ final Key leadingKey = GlobalKey ();
1373
+ final Key trailingKey = GlobalKey ();
1374
+ const double leadingHeight = 24.0 ;
1375
+ const double titleHeight = 50.0 ;
1376
+ const double trailingHeight = 24.0 ;
1377
+ const double minVerticalPadding = 10.0 ;
1378
+ const double tileHeight = minVerticalPadding * 2 + titleHeight;
1379
+
1380
+ Widget buildFrame ({ ListTileTitleAlignment ? titleAlignment }) {
1381
+ return MaterialApp (
1382
+ theme: ThemeData (useMaterial3: true ),
1383
+ home: Material (
1384
+ child: Center (
1385
+ child: CheckboxListTile (
1386
+ titleAlignment: titleAlignment,
1387
+ minVerticalPadding: minVerticalPadding,
1388
+ title: const SizedBox (width: 20.0 , height: titleHeight),
1389
+ value: false ,
1390
+ onChanged: (bool ? value) {},
1391
+ ),
1392
+ ),
1393
+ ),
1394
+ );
1395
+ }
1396
+
1397
+ // If [ThemeData.useMaterial3] is true, the default title alignment is
1398
+ // [ListTileTitleAlignment.threeLine], which positions the leading and
1399
+ // trailing widgets center vertically in the tile if the [ListTile.isThreeLine]
1400
+ // property is false.
1401
+ await tester.pumpWidget (buildFrame ());
1402
+ Offset tileOffset = tester.getTopLeft (find.byType (ListTile ));
1403
+ Offset leadingOffset = tester.getTopLeft (find.byKey (leadingKey));
1404
+ Offset trailingOffset = tester.getTopRight (find.byKey (trailingKey));
1405
+
1406
+ // Leading and trailing widgets are centered vertically in the tile.
1407
+ const double centerPosition = (tileHeight / 2 ) - (leadingHeight / 2 );
1408
+ expect (leadingOffset.dy - tileOffset.dy, centerPosition);
1409
+ expect (trailingOffset.dy - tileOffset.dy, centerPosition);
1410
+
1411
+ // Test [ListTileTitleAlignment.threeLine] alignment.
1412
+ await tester.pumpWidget (buildFrame (titleAlignment: ListTileTitleAlignment .threeLine));
1413
+ tileOffset = tester.getTopLeft (find.byType (ListTile ));
1414
+ leadingOffset = tester.getTopLeft (find.byKey (leadingKey));
1415
+ trailingOffset = tester.getTopRight (find.byKey (trailingKey));
1416
+
1417
+ // Leading and trailing widgets are centered vertically in the tile,
1418
+ // If the [ListTile.isThreeLine] property is false.
1419
+ expect (leadingOffset.dy - tileOffset.dy, centerPosition);
1420
+ expect (trailingOffset.dy - tileOffset.dy, centerPosition);
1421
+
1422
+ // Test [ListTileTitleAlignment.titleHeight] alignment.
1423
+ await tester.pumpWidget (buildFrame (titleAlignment: ListTileTitleAlignment .titleHeight));
1424
+ tileOffset = tester.getTopLeft (find.byType (ListTile ));
1425
+ leadingOffset = tester.getTopLeft (find.byKey (leadingKey));
1426
+ trailingOffset = tester.getTopRight (find.byKey (trailingKey));
1427
+
1428
+ // If the tile height is less than 72.0 pixels, the leading widget is placed
1429
+ // 16.0 pixels below the top of the title widget, and the trailing is centered
1430
+ // vertically in the tile.
1431
+ const double titlePosition = 16.0 ;
1432
+ expect (leadingOffset.dy - tileOffset.dy, titlePosition);
1433
+ expect (trailingOffset.dy - tileOffset.dy, centerPosition);
1434
+
1435
+ // Test [ListTileTitleAlignment.top] alignment.
1436
+ await tester.pumpWidget (buildFrame (titleAlignment: ListTileTitleAlignment .top));
1437
+ tileOffset = tester.getTopLeft (find.byType (ListTile ));
1438
+ leadingOffset = tester.getTopLeft (find.byKey (leadingKey));
1439
+ trailingOffset = tester.getTopRight (find.byKey (trailingKey));
1440
+
1441
+ // Leading and trailing widgets are placed minVerticalPadding below
1442
+ // the top of the title widget.
1443
+ const double topPosition = minVerticalPadding;
1444
+ expect (leadingOffset.dy - tileOffset.dy, topPosition);
1445
+ expect (trailingOffset.dy - tileOffset.dy, topPosition);
1446
+
1447
+ // Test [ListTileTitleAlignment.center] alignment.
1448
+ await tester.pumpWidget (buildFrame (titleAlignment: ListTileTitleAlignment .center));
1449
+ tileOffset = tester.getTopLeft (find.byType (ListTile ));
1450
+ leadingOffset = tester.getTopLeft (find.byKey (leadingKey));
1451
+ trailingOffset = tester.getTopRight (find.byKey (trailingKey));
1452
+
1453
+ // Leading and trailing widgets are centered vertically in the tile.
1454
+ expect (leadingOffset.dy - tileOffset.dy, centerPosition);
1455
+ expect (trailingOffset.dy - tileOffset.dy, centerPosition);
1456
+
1457
+ // Test [ListTileTitleAlignment.bottom] alignment.
1458
+ await tester.pumpWidget (buildFrame (titleAlignment: ListTileTitleAlignment .bottom));
1459
+ tileOffset = tester.getTopLeft (find.byType (ListTile ));
1460
+ leadingOffset = tester.getTopLeft (find.byKey (leadingKey));
1461
+ trailingOffset = tester.getTopRight (find.byKey (trailingKey));
1462
+
1463
+ // Leading and trailing widgets are placed minVerticalPadding above
1464
+ // the bottom of the subtitle widget.
1465
+ const double bottomPosition = tileHeight - minVerticalPadding - leadingHeight;
1466
+ expect (leadingOffset.dy - tileOffset.dy, bottomPosition);
1467
+ expect (trailingOffset.dy - tileOffset.dy, bottomPosition);
1468
+ });
1469
+
1470
+ testWidgets ('CheckboxListTile horizontalTitleGap = 0.0' , (WidgetTester tester) async {
1471
+ Widget buildFrame (TextDirection textDirection, { double ? themeHorizontalTitleGap, double ? widgetHorizontalTitleGap }) {
1472
+ return MaterialApp (
1473
+ theme: ThemeData (useMaterial3: false ),
1474
+ home: Directionality (
1475
+ textDirection: textDirection,
1476
+ child: Material (
1477
+ child: ListTileTheme (
1478
+ data: ListTileThemeData (horizontalTitleGap: themeHorizontalTitleGap),
1479
+ child: Container (
1480
+ alignment: Alignment .topLeft,
1481
+ child: CheckboxListTile (
1482
+ horizontalTitleGap: widgetHorizontalTitleGap,
1483
+ title: const Text ('title' ),
1484
+ value: false ,
1485
+ onChanged: (bool ? value) {},
1486
+ ),
1487
+ ),
1488
+ ),
1489
+ ),
1490
+ ),
1491
+ );
1492
+ }
1493
+
1494
+ double left (String text) => tester.getTopLeft (find.text (text)).dx;
1495
+ double right (String text) => tester.getTopRight (find.text (text)).dx;
1496
+
1497
+ await tester.pumpWidget (buildFrame (TextDirection .ltr, widgetHorizontalTitleGap: 0 ));
1498
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1499
+ expect (left ('title' ), 56.0 );
1500
+
1501
+ await tester.pumpWidget (buildFrame (TextDirection .ltr, themeHorizontalTitleGap: 0 ));
1502
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1503
+ expect (left ('title' ), 56.0 );
1504
+
1505
+ await tester.pumpWidget (buildFrame (TextDirection .ltr, themeHorizontalTitleGap: 10 , widgetHorizontalTitleGap: 0 ));
1506
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1507
+ expect (left ('title' ), 56.0 );
1508
+
1509
+ await tester.pumpWidget (buildFrame (TextDirection .rtl, widgetHorizontalTitleGap: 0 ));
1510
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1511
+ expect (right ('title' ), 744.0 );
1512
+
1513
+ await tester.pumpWidget (buildFrame (TextDirection .rtl, themeHorizontalTitleGap: 0 ));
1514
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1515
+ expect (right ('title' ), 744.0 );
1516
+
1517
+ await tester.pumpWidget (buildFrame (TextDirection .rtl, themeHorizontalTitleGap: 10 , widgetHorizontalTitleGap: 0 ));
1518
+ expect (tester.getSize (find.byType (ListTile )), const Size (800.0 , 56.0 ));
1519
+ expect (right ('title' ), 744.0 );
1520
+ });
1521
+
1237
1522
testWidgets ('CheckboxListTile uses ListTileTheme controlAffinity' , (WidgetTester tester) async {
1238
1523
Widget buildListTile (ListTileControlAffinity controlAffinity) {
1239
1524
return MaterialApp (
0 commit comments