mirror of
https://github.com/flutter/flutter
synced 2024-08-24 18:36:03 +00:00
Introduce avatarBoxConstraints
& deleteIconBoxConstraints
for the chips (#143302)
fixes [Chip widget's avatar padding changing if label text is more than 1 line](https://github.com/flutter/flutter/issues/136892) ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; List<String> strings = [ 'hello good morning', 'hello good morning hello good morning', 'hello good morning hello good morning hello good morning' ]; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( body: Center( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ const Text( 'avatarBoxConstraints: null \ndeleteIconBoxConstraints: null', textAlign: TextAlign.center), for (String string in strings) Padding( padding: const EdgeInsets.all(8.0), child: RawChip( label: Container( width: 150, color: Colors.amber, child: Text( string, maxLines: 3, overflow: TextOverflow.ellipsis, ), ), avatar: const Icon(Icons.settings), onDeleted: () {}, ), ), ], ), Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ const Text( 'avatarBoxConstraints: BoxConstraints.tightForFinite() \ndeleteIconBoxConstraints: BoxConstraints.tightForFinite()', textAlign: TextAlign.center), for (String string in strings) Padding( padding: const EdgeInsets.all(8.0), child: RawChip( avatarBoxConstraints: const BoxConstraints.tightForFinite(), deleteIconBoxConstraints: const BoxConstraints.tightForFinite(), label: Container( width: 150, color: Colors.amber, child: Text( string, maxLines: 3, overflow: TextOverflow.ellipsis, ), ), avatar: const Icon(Icons.settings), onDeleted: () {}, ), ), ], ), ], ), ), ), ); } } ``` </details> ### Preview ![Screenshot 2024-02-12 at 14 58 35](https://github.com/flutter/flutter/assets/48603081/5724bd07-7ac7-4987-b992-fa3ab8488273) # Example previews ![Screenshot 2024-02-12 at 22 15 14](https://github.com/flutter/flutter/assets/48603081/33af472d-3561-47d4-8d0d-e1628de1e0aa) ![Screenshot 2024-02-12 at 22 15 46](https://github.com/flutter/flutter/assets/48603081/3de78b59-5cb6-4fd8-879b-8e204aacb069)
This commit is contained in:
parent
a8e9f209a1
commit
ccf42dde88
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2014 The Flutter 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/material.dart';
|
||||
|
||||
/// Flutter code sample for [ChipAttributes.avatarBoxConstraints].
|
||||
|
||||
void main() => runApp(const AvatarBoxConstraintsApp());
|
||||
|
||||
class AvatarBoxConstraintsApp extends StatelessWidget {
|
||||
const AvatarBoxConstraintsApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: AvatarBoxConstraintsExample(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AvatarBoxConstraintsExample extends StatelessWidget {
|
||||
const AvatarBoxConstraintsExample({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
RawChip(
|
||||
avatarBoxConstraints: BoxConstraints.tightForFinite(),
|
||||
avatar: Icon(Icons.star),
|
||||
label: SizedBox(
|
||||
width: 150,
|
||||
child: Text(
|
||||
'One line text.',
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
RawChip(
|
||||
avatarBoxConstraints: BoxConstraints.tightForFinite(),
|
||||
avatar: Icon(Icons.star),
|
||||
label: SizedBox(
|
||||
width: 150,
|
||||
child: Text(
|
||||
'This text will wrap into two lines.',
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
RawChip(
|
||||
avatarBoxConstraints: BoxConstraints.tightForFinite(),
|
||||
avatar: Icon(Icons.star),
|
||||
label: SizedBox(
|
||||
width: 150,
|
||||
child: Text(
|
||||
'This is a very long text that will wrap into three lines.',
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2014 The Flutter 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/material.dart';
|
||||
|
||||
/// Flutter code sample for [DeletableChipAttributes.deleteIconBoxConstraints].
|
||||
|
||||
void main() => runApp(const DeleteIconBoxConstraintsApp());
|
||||
|
||||
class DeleteIconBoxConstraintsApp extends StatelessWidget {
|
||||
const DeleteIconBoxConstraintsApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: DeleteIconBoxConstraintsExample(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DeleteIconBoxConstraintsExample extends StatelessWidget {
|
||||
const DeleteIconBoxConstraintsExample({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
RawChip(
|
||||
deleteIconBoxConstraints: const BoxConstraints.tightForFinite(),
|
||||
onDeleted: () {},
|
||||
label: const SizedBox(
|
||||
width: 150,
|
||||
child: Text(
|
||||
'One line text.',
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
RawChip(
|
||||
deleteIconBoxConstraints: const BoxConstraints.tightForFinite(),
|
||||
onDeleted: () {},
|
||||
label: const SizedBox(
|
||||
width: 150,
|
||||
child: Text(
|
||||
'This text will wrap into two lines.',
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
RawChip(
|
||||
deleteIconBoxConstraints: const BoxConstraints.tightForFinite(),
|
||||
onDeleted: () {},
|
||||
label: const SizedBox(
|
||||
width: 150,
|
||||
child: Text(
|
||||
'This is a very long text that will wrap into three lines.',
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2014 The Flutter 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/material.dart';
|
||||
import 'package:flutter_api_samples/material/chip/chip_attributes.avatar_box_constraints.0.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('RawChip.avatarBoxConstraints updates avatar size constraints', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double padding = 8.0;
|
||||
|
||||
await tester.pumpWidget(
|
||||
const example.AvatarBoxConstraintsApp(),
|
||||
);
|
||||
|
||||
expect(tester.getSize(find.byType(RawChip).at(0)).width, equals(202.0));
|
||||
expect(tester.getSize(find.byType(RawChip).at(0)).height, equals(58.0));
|
||||
|
||||
Offset chipTopLeft = tester.getTopLeft(find.byWidget(tester.widget<Material>(
|
||||
find.descendant(
|
||||
of: find.byType(RawChip).at(0),
|
||||
matching: find.byType(Material),
|
||||
),
|
||||
)));
|
||||
Offset avatarCenter = tester.getCenter(find.byIcon(Icons.star).at(0));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (iconSize / 2) - padding - border);
|
||||
|
||||
expect(tester.getSize(find.byType(RawChip).at(1)).width, equals(202.0));
|
||||
expect(tester.getSize(find.byType(RawChip).at(1)).height, equals(78.0));
|
||||
|
||||
chipTopLeft = tester.getTopLeft(find.byWidget(tester.widget<Material>(
|
||||
find.descendant(
|
||||
of: find.byType(RawChip).at(1),
|
||||
matching: find.byType(Material),
|
||||
),
|
||||
)));
|
||||
avatarCenter = tester.getCenter(find.byIcon(Icons.star).at(1));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (iconSize / 2) - padding - border);
|
||||
|
||||
expect(tester.getSize(find.byType(RawChip).at(2)).width, equals(202.0));
|
||||
expect(tester.getSize(find.byType(RawChip).at(2)).height, equals(78.0));
|
||||
|
||||
chipTopLeft = tester.getTopLeft(find.byWidget(tester.widget<Material>(
|
||||
find.descendant(
|
||||
of: find.byType(RawChip).at(2),
|
||||
matching: find.byType(Material),
|
||||
),
|
||||
)));
|
||||
avatarCenter = tester.getCenter(find.byIcon(Icons.star).at(2));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (iconSize / 2) - padding - border);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2014 The Flutter 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/material.dart';
|
||||
import 'package:flutter_api_samples/material/chip/deletable_chip_attributes.delete_icon_box_constraints.0.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('RawChip.deleteIconBoxConstraints updates delete icon size constraints', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double padding = 8.0;
|
||||
|
||||
await tester.pumpWidget(
|
||||
const example.DeleteIconBoxConstraintsApp(),
|
||||
);
|
||||
|
||||
expect(tester.getSize(find.byType(RawChip).at(0)).width, equals(202.0));
|
||||
expect(tester.getSize(find.byType(RawChip).at(0)).height, equals(58.0));
|
||||
|
||||
Offset chipToRight = tester.getTopRight(find.byWidget(tester.widget<Material>(
|
||||
find.descendant(
|
||||
of: find.byType(RawChip).at(0),
|
||||
matching: find.byType(Material),
|
||||
),
|
||||
)));
|
||||
Offset deleteIconCenter = tester.getCenter(find.byIcon(Icons.cancel).at(0));
|
||||
expect(chipToRight.dx, deleteIconCenter.dx + (iconSize / 2) + padding + border);
|
||||
|
||||
expect(tester.getSize(find.byType(RawChip).at(1)).width, equals(202.0));
|
||||
expect(tester.getSize(find.byType(RawChip).at(1)).height, equals(78.0));
|
||||
|
||||
chipToRight = tester.getTopRight(find.byWidget(tester.widget<Material>(
|
||||
find.descendant(
|
||||
of: find.byType(RawChip).at(1),
|
||||
matching: find.byType(Material),
|
||||
),
|
||||
)));
|
||||
deleteIconCenter = tester.getCenter(find.byIcon(Icons.cancel).at(1));
|
||||
expect(chipToRight.dx, deleteIconCenter.dx + (iconSize / 2) + padding + border);
|
||||
|
||||
expect(tester.getSize(find.byType(RawChip).at(2)).width, equals(202.0));
|
||||
expect(tester.getSize(find.byType(RawChip).at(2)).height, equals(78.0));
|
||||
|
||||
chipToRight = tester.getTopRight(find.byWidget(tester.widget<Material>(
|
||||
find.descendant(
|
||||
of: find.byType(RawChip).at(2),
|
||||
matching: find.byType(Material),
|
||||
),
|
||||
)));
|
||||
deleteIconCenter = tester.getCenter(find.byIcon(Icons.cancel).at(2));
|
||||
expect(chipToRight.dx, deleteIconCenter.dx + (iconSize / 2) + padding + border);
|
||||
});
|
||||
}
|
|
@ -109,6 +109,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||
this.shadowColor,
|
||||
this.surfaceTintColor,
|
||||
this.iconTheme,
|
||||
this.avatarBoxConstraints,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_chipVariant = _ChipVariant.flat;
|
||||
|
@ -143,6 +144,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||
this.shadowColor,
|
||||
this.surfaceTintColor,
|
||||
this.iconTheme,
|
||||
this.avatarBoxConstraints,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_chipVariant = _ChipVariant.elevated;
|
||||
|
@ -191,6 +193,8 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||
final Color? surfaceTintColor;
|
||||
@override
|
||||
final IconThemeData? iconTheme;
|
||||
@override
|
||||
final BoxConstraints? avatarBoxConstraints;
|
||||
|
||||
@override
|
||||
bool get isEnabled => onPressed != null;
|
||||
|
@ -228,6 +232,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||
shadowColor: shadowColor,
|
||||
surfaceTintColor: surfaceTintColor,
|
||||
iconTheme: iconTheme,
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -225,6 +225,22 @@ abstract interface class ChipAttributes {
|
|||
/// color and a size of 18.0 is used when the chip is disabled. Otherwise,
|
||||
/// it defaults to null.
|
||||
IconThemeData? get iconTheme;
|
||||
|
||||
/// Optional size constraints for the avatar.
|
||||
///
|
||||
/// When unspecified, defaults to a minimum size of chip height or label height
|
||||
/// (whichever is greater) and a padding of 8.0 pixels on all sides.
|
||||
///
|
||||
/// The default constraints ensure that the avatar is accessible.
|
||||
/// Specifying this parameter enables creation of avatar smaller than
|
||||
/// the minimum size, but it is not recommended.
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
/// This sample shows how to use [avatarBoxConstraints] to adjust avatar size constraints
|
||||
///
|
||||
/// ** See code in examples/api/lib/material/chip/chip_attributes.avatar_box_constraints.0.dart **
|
||||
/// {@end-tool}
|
||||
BoxConstraints? get avatarBoxConstraints;
|
||||
}
|
||||
|
||||
/// An interface for Material Design chips that can be deleted.
|
||||
|
@ -283,6 +299,23 @@ abstract interface class DeletableChipAttributes {
|
|||
///
|
||||
/// If the chip is disabled, the delete button tooltip will not be shown.
|
||||
String? get deleteButtonTooltipMessage;
|
||||
|
||||
/// Optional size constraints for the delete icon.
|
||||
///
|
||||
/// When unspecified, defaults to a minimum size of chip height or label height
|
||||
/// (whichever is greater) and a padding of 8.0 pixels on all sides.
|
||||
///
|
||||
/// The default constraints ensure that the delete icon is accessible.
|
||||
/// Specifying this parameter enables creation of delete icon smaller than
|
||||
/// the minimum size, but it is not recommended.
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
/// This sample shows how to use [deleteIconBoxConstraints] to adjust delete icon
|
||||
/// size constraints.
|
||||
///
|
||||
/// ** See code in examples/api/lib/material/chip/deletable_chip_attributes.delete_icon_box_constraints.0.dart **
|
||||
/// {@end-tool}
|
||||
BoxConstraints? get deleteIconBoxConstraints;
|
||||
}
|
||||
|
||||
/// An interface for Material Design chips that can have check marks.
|
||||
|
@ -590,6 +623,8 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
|||
this.shadowColor,
|
||||
this.surfaceTintColor,
|
||||
this.iconTheme,
|
||||
this.avatarBoxConstraints,
|
||||
this.deleteIconBoxConstraints,
|
||||
}) : assert(elevation == null || elevation >= 0.0);
|
||||
|
||||
@override
|
||||
|
@ -636,6 +671,10 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
|||
final Color? surfaceTintColor;
|
||||
@override
|
||||
final IconThemeData? iconTheme;
|
||||
@override
|
||||
final BoxConstraints? avatarBoxConstraints;
|
||||
@override
|
||||
final BoxConstraints? deleteIconBoxConstraints;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -664,6 +703,8 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
|||
shadowColor: shadowColor,
|
||||
surfaceTintColor: surfaceTintColor,
|
||||
iconTheme: iconTheme,
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -751,6 +792,8 @@ class RawChip extends StatefulWidget
|
|||
this.showCheckmark,
|
||||
this.checkmarkColor,
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
this.avatarBoxConstraints,
|
||||
this.deleteIconBoxConstraints,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
deleteIcon = deleteIcon ?? _kDefaultDeleteIcon;
|
||||
|
@ -830,6 +873,10 @@ class RawChip extends StatefulWidget
|
|||
final Color? checkmarkColor;
|
||||
@override
|
||||
final ShapeBorder avatarBorder;
|
||||
@override
|
||||
final BoxConstraints? avatarBoxConstraints;
|
||||
@override
|
||||
final BoxConstraints? deleteIconBoxConstraints;
|
||||
|
||||
/// If set, this indicates that the chip should be disabled if all of the
|
||||
/// tap callbacks ([onSelected], [onPressed]) are null.
|
||||
|
@ -1205,6 +1252,10 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
|
|||
final IconThemeData? iconTheme = widget.iconTheme
|
||||
?? chipTheme.iconTheme
|
||||
?? chipDefaults.iconTheme;
|
||||
final BoxConstraints? avatarBoxConstraints = widget.avatarBoxConstraints
|
||||
?? chipTheme.avatarBoxConstraints;
|
||||
final BoxConstraints? deleteIconBoxConstraints = widget.deleteIconBoxConstraints
|
||||
?? chipTheme.deleteIconBoxConstraints;
|
||||
|
||||
final TextStyle effectiveLabelStyle = labelStyle.merge(widget.labelStyle);
|
||||
final Color? resolvedLabelColor = MaterialStateProperty.resolveAs<Color?>(effectiveLabelStyle.color, materialStates);
|
||||
|
@ -1300,6 +1351,8 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
|
|||
deleteDrawerAnimation: deleteDrawerAnimation,
|
||||
isEnabled: widget.isEnabled,
|
||||
avatarBorder: widget.avatarBorder,
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -1423,6 +1476,8 @@ class _ChipRenderWidget extends SlottedMultiChildRenderObjectWidget<_ChipSlot, R
|
|||
required this.deleteDrawerAnimation,
|
||||
required this.enableAnimation,
|
||||
this.avatarBorder,
|
||||
this.avatarBoxConstraints,
|
||||
this.deleteIconBoxConstraints,
|
||||
});
|
||||
|
||||
final _ChipRenderTheme theme;
|
||||
|
@ -1433,6 +1488,8 @@ class _ChipRenderWidget extends SlottedMultiChildRenderObjectWidget<_ChipSlot, R
|
|||
final Animation<double> deleteDrawerAnimation;
|
||||
final Animation<double> enableAnimation;
|
||||
final ShapeBorder? avatarBorder;
|
||||
final BoxConstraints? avatarBoxConstraints;
|
||||
final BoxConstraints? deleteIconBoxConstraints;
|
||||
|
||||
@override
|
||||
Iterable<_ChipSlot> get slots => _ChipSlot.values;
|
||||
|
@ -1457,7 +1514,9 @@ class _ChipRenderWidget extends SlottedMultiChildRenderObjectWidget<_ChipSlot, R
|
|||
..avatarDrawerAnimation = avatarDrawerAnimation
|
||||
..deleteDrawerAnimation = deleteDrawerAnimation
|
||||
..enableAnimation = enableAnimation
|
||||
..avatarBorder = avatarBorder;
|
||||
..avatarBorder = avatarBorder
|
||||
..avatarBoxConstraints = avatarBoxConstraints
|
||||
..deleteIconBoxConstraints = deleteIconBoxConstraints;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1472,6 +1531,8 @@ class _ChipRenderWidget extends SlottedMultiChildRenderObjectWidget<_ChipSlot, R
|
|||
deleteDrawerAnimation: deleteDrawerAnimation,
|
||||
enableAnimation: enableAnimation,
|
||||
avatarBorder: avatarBorder,
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1557,8 +1618,12 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
|
|||
required this.deleteDrawerAnimation,
|
||||
required this.enableAnimation,
|
||||
this.avatarBorder,
|
||||
BoxConstraints? avatarBoxConstraints,
|
||||
BoxConstraints? deleteIconBoxConstraints,
|
||||
}) : _theme = theme,
|
||||
_textDirection = textDirection;
|
||||
_textDirection = textDirection,
|
||||
_avatarBoxConstraints = avatarBoxConstraints,
|
||||
_deleteIconBoxConstraints = deleteIconBoxConstraints;
|
||||
|
||||
bool? value;
|
||||
bool? isEnabled;
|
||||
|
@ -1594,6 +1659,26 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
|
|||
markNeedsLayout();
|
||||
}
|
||||
|
||||
BoxConstraints? get avatarBoxConstraints => _avatarBoxConstraints;
|
||||
BoxConstraints? _avatarBoxConstraints;
|
||||
set avatarBoxConstraints(BoxConstraints? value) {
|
||||
if (_avatarBoxConstraints == value) {
|
||||
return;
|
||||
}
|
||||
_avatarBoxConstraints = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
BoxConstraints? get deleteIconBoxConstraints => _deleteIconBoxConstraints;
|
||||
BoxConstraints? _deleteIconBoxConstraints;
|
||||
set deleteIconBoxConstraints(BoxConstraints? value) {
|
||||
if (_deleteIconBoxConstraints == value) {
|
||||
return;
|
||||
}
|
||||
_deleteIconBoxConstraints = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
// The returned list is ordered for hit testing.
|
||||
@override
|
||||
Iterable<RenderBox> get children {
|
||||
|
@ -1712,9 +1797,9 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
|
|||
);
|
||||
}
|
||||
|
||||
Size _layoutAvatar(BoxConstraints contentConstraints, double contentSize, [ChildLayouter layoutChild = ChildLayoutHelper.layoutChild]) {
|
||||
Size _layoutAvatar(double contentSize, [ChildLayouter layoutChild = ChildLayoutHelper.layoutChild]) {
|
||||
final double requestedSize = math.max(0.0, contentSize);
|
||||
final BoxConstraints avatarConstraints = BoxConstraints.tightFor(
|
||||
final BoxConstraints avatarConstraints = avatarBoxConstraints ?? BoxConstraints.tightFor(
|
||||
width: requestedSize,
|
||||
height: requestedSize,
|
||||
);
|
||||
|
@ -1733,9 +1818,9 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
|
|||
return Size(avatarWidth, avatarHeight);
|
||||
}
|
||||
|
||||
Size _layoutDeleteIcon(BoxConstraints contentConstraints, double contentSize, [ChildLayouter layoutChild = ChildLayoutHelper.layoutChild]) {
|
||||
Size _layoutDeleteIcon(double contentSize, [ChildLayouter layoutChild = ChildLayoutHelper.layoutChild]) {
|
||||
final double requestedSize = math.max(0.0, contentSize);
|
||||
final BoxConstraints deleteIconConstraints = BoxConstraints.tightFor(
|
||||
final BoxConstraints deleteIconConstraints = deleteIconBoxConstraints ?? BoxConstraints.tightFor(
|
||||
width: requestedSize,
|
||||
height: requestedSize,
|
||||
);
|
||||
|
@ -1795,8 +1880,8 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
|
|||
_kChipHeight - theme.padding.vertical + theme.labelPadding.vertical,
|
||||
rawLabelSize.height + theme.labelPadding.vertical,
|
||||
);
|
||||
final Size avatarSize = _layoutAvatar(contentConstraints, contentSize, layoutChild);
|
||||
final Size deleteIconSize = _layoutDeleteIcon(contentConstraints, contentSize, layoutChild);
|
||||
final Size avatarSize = _layoutAvatar(contentSize, layoutChild);
|
||||
final Size deleteIconSize = _layoutDeleteIcon(contentSize, layoutChild);
|
||||
final Size labelSize = _layoutLabel(
|
||||
contentConstraints,
|
||||
avatarSize.width + deleteIconSize.width,
|
||||
|
|
|
@ -198,6 +198,8 @@ class ChipThemeData with Diagnosticable {
|
|||
this.elevation,
|
||||
this.pressElevation,
|
||||
this.iconTheme,
|
||||
this.avatarBoxConstraints,
|
||||
this.deleteIconBoxConstraints,
|
||||
});
|
||||
|
||||
/// Generates a ChipThemeData from a brightness, a primary color, and a text
|
||||
|
@ -436,6 +438,19 @@ class ChipThemeData with Diagnosticable {
|
|||
/// [FilterChip], [InputChip], [RawChip].
|
||||
final IconThemeData? iconTheme;
|
||||
|
||||
/// Overrides the default for [ChipAttributes.avatarBoxConstraints],
|
||||
/// the size constraints for the avatar widget.
|
||||
///
|
||||
/// This property applies to [ActionChip], [Chip], [ChoiceChip],
|
||||
/// [FilterChip], [InputChip], [RawChip].
|
||||
final BoxConstraints? avatarBoxConstraints;
|
||||
|
||||
/// Overrides the default for [DeletableChipAttributes.deleteIconBoxConstraints].
|
||||
/// the size constraints for the delete icon widget.
|
||||
///
|
||||
/// This property applies to [Chip], [FilterChip], [InputChip], [RawChip].
|
||||
final BoxConstraints? deleteIconBoxConstraints;
|
||||
|
||||
/// Creates a copy of this object but with the given fields replaced with the
|
||||
/// new values.
|
||||
ChipThemeData copyWith({
|
||||
|
@ -460,6 +475,8 @@ class ChipThemeData with Diagnosticable {
|
|||
double? elevation,
|
||||
double? pressElevation,
|
||||
IconThemeData? iconTheme,
|
||||
BoxConstraints? avatarBoxConstraints,
|
||||
BoxConstraints? deleteIconBoxConstraints,
|
||||
}) {
|
||||
return ChipThemeData(
|
||||
color: color ?? this.color,
|
||||
|
@ -483,6 +500,8 @@ class ChipThemeData with Diagnosticable {
|
|||
elevation: elevation ?? this.elevation,
|
||||
pressElevation: pressElevation ?? this.pressElevation,
|
||||
iconTheme: iconTheme ?? this.iconTheme,
|
||||
avatarBoxConstraints: avatarBoxConstraints ?? this.avatarBoxConstraints,
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints ?? this.deleteIconBoxConstraints,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -517,6 +536,8 @@ class ChipThemeData with Diagnosticable {
|
|||
iconTheme: a?.iconTheme != null || b?.iconTheme != null
|
||||
? IconThemeData.lerp(a?.iconTheme, b?.iconTheme, t)
|
||||
: null,
|
||||
avatarBoxConstraints: BoxConstraints.lerp(a?.avatarBoxConstraints, b?.avatarBoxConstraints, t),
|
||||
deleteIconBoxConstraints: BoxConstraints.lerp(a?.deleteIconBoxConstraints, b?.deleteIconBoxConstraints, t),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -565,6 +586,8 @@ class ChipThemeData with Diagnosticable {
|
|||
elevation,
|
||||
pressElevation,
|
||||
iconTheme,
|
||||
avatarBoxConstraints,
|
||||
deleteIconBoxConstraints,
|
||||
]);
|
||||
|
||||
@override
|
||||
|
@ -596,7 +619,9 @@ class ChipThemeData with Diagnosticable {
|
|||
&& other.brightness == brightness
|
||||
&& other.elevation == elevation
|
||||
&& other.pressElevation == pressElevation
|
||||
&& other.iconTheme == iconTheme;
|
||||
&& other.iconTheme == iconTheme
|
||||
&& other.avatarBoxConstraints == avatarBoxConstraints
|
||||
&& other.deleteIconBoxConstraints == deleteIconBoxConstraints;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -623,5 +648,7 @@ class ChipThemeData with Diagnosticable {
|
|||
properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
|
||||
properties.add(DoubleProperty('pressElevation', pressElevation, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<IconThemeData>('iconTheme', iconTheme, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<BoxConstraints>('avatarBoxConstraints', avatarBoxConstraints, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<BoxConstraints>('deleteIconBoxConstraints', deleteIconBoxConstraints, defaultValue: null));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ class ChoiceChip extends StatelessWidget
|
|||
this.showCheckmark,
|
||||
this.checkmarkColor,
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
this.avatarBoxConstraints,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_chipVariant = _ChipVariant.flat;
|
||||
|
@ -132,6 +133,7 @@ class ChoiceChip extends StatelessWidget
|
|||
this.showCheckmark,
|
||||
this.checkmarkColor,
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
this.avatarBoxConstraints,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_chipVariant = _ChipVariant.elevated;
|
||||
|
@ -192,6 +194,8 @@ class ChoiceChip extends StatelessWidget
|
|||
final ShapeBorder avatarBorder;
|
||||
@override
|
||||
final IconThemeData? iconTheme;
|
||||
@override
|
||||
final BoxConstraints? avatarBoxConstraints;
|
||||
|
||||
@override
|
||||
bool get isEnabled => onSelected != null;
|
||||
|
@ -236,6 +240,7 @@ class ChoiceChip extends StatelessWidget
|
|||
selectedShadowColor: selectedShadowColor,
|
||||
avatarBorder: avatarBorder,
|
||||
iconTheme: iconTheme,
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,6 +101,8 @@ class FilterChip extends StatelessWidget
|
|||
this.showCheckmark,
|
||||
this.checkmarkColor,
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
this.avatarBoxConstraints,
|
||||
this.deleteIconBoxConstraints,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_chipVariant = _ChipVariant.flat;
|
||||
|
@ -145,6 +147,8 @@ class FilterChip extends StatelessWidget
|
|||
this.showCheckmark,
|
||||
this.checkmarkColor,
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
this.avatarBoxConstraints,
|
||||
this.deleteIconBoxConstraints,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
_chipVariant = _ChipVariant.elevated;
|
||||
|
@ -213,6 +217,10 @@ class FilterChip extends StatelessWidget
|
|||
final ShapeBorder avatarBorder;
|
||||
@override
|
||||
final IconThemeData? iconTheme;
|
||||
@override
|
||||
final BoxConstraints? avatarBoxConstraints;
|
||||
@override
|
||||
final BoxConstraints? deleteIconBoxConstraints;
|
||||
|
||||
@override
|
||||
bool get isEnabled => onSelected != null;
|
||||
|
@ -262,6 +270,8 @@ class FilterChip extends StatelessWidget
|
|||
checkmarkColor: checkmarkColor,
|
||||
avatarBorder: avatarBorder,
|
||||
iconTheme: iconTheme,
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,8 @@ class InputChip extends StatelessWidget
|
|||
this.showCheckmark,
|
||||
this.checkmarkColor,
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
this.avatarBoxConstraints,
|
||||
this.deleteIconBoxConstraints,
|
||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0);
|
||||
|
||||
|
@ -193,6 +195,10 @@ class InputChip extends StatelessWidget
|
|||
final ShapeBorder avatarBorder;
|
||||
@override
|
||||
final IconThemeData? iconTheme;
|
||||
@override
|
||||
final BoxConstraints? avatarBoxConstraints;
|
||||
@override
|
||||
final BoxConstraints? deleteIconBoxConstraints;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -238,6 +244,8 @@ class InputChip extends StatelessWidget
|
|||
isEnabled: isEnabled && (onSelected != null || onDeleted != null || onPressed != null),
|
||||
avatarBorder: avatarBorder,
|
||||
iconTheme: iconTheme,
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -437,4 +437,60 @@ void main() {
|
|||
|
||||
expect(getIconData(tester).color, const Color(0xff00ff00));
|
||||
});
|
||||
|
||||
testWidgets('ActionChip avatar layout constraints can be customized', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double labelPadding = 8.0;
|
||||
const double padding = 8.0;
|
||||
const Size labelSize = Size(100, 100);
|
||||
|
||||
Widget buildChip({BoxConstraints? avatarBoxConstraints}) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: ActionChip(
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
avatar: const Icon(Icons.favorite),
|
||||
label: Container(
|
||||
width: labelSize.width,
|
||||
height: labelSize.width,
|
||||
color: const Color(0xFFFF0000),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test default avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip());
|
||||
|
||||
expect(tester.getSize(find.byType(ActionChip)).width, equals(234.0));
|
||||
expect(tester.getSize(find.byType(ActionChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
Offset chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
final Offset avatarCenter = tester.getCenter(find.byIcon(Icons.favorite));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (labelSize.width / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between avatar and label.
|
||||
Offset labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (labelSize.width / 2) + labelPadding);
|
||||
|
||||
// Test custom avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip(avatarBoxConstraints: const BoxConstraints.tightForFinite()));
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(find.byType(ActionChip)).width, equals(152.0));
|
||||
expect(tester.getSize(find.byType(ActionChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (iconSize / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between avatar and label.
|
||||
labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (iconSize / 2) + labelPadding);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5088,7 +5088,7 @@ void main() {
|
|||
});
|
||||
},
|
||||
child: Text('${isEnabled ? 'Disable' : 'Enable'} Chip'),
|
||||
)
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
@ -5119,7 +5119,7 @@ void main() {
|
|||
isEnabled: false,
|
||||
label: const Text('Label'),
|
||||
onDeleted: () { },
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -5134,7 +5134,7 @@ void main() {
|
|||
isEnabled: enabled,
|
||||
label: const Text('Label'),
|
||||
onDeleted: () { },
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -5157,6 +5157,234 @@ void main() {
|
|||
expect(findTooltipContainer('Delete'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('Chip avatar layout constraints can be customized', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double labelPadding = 8.0;
|
||||
const double padding = 8.0;
|
||||
const Size labelSize = Size(100, 100);
|
||||
|
||||
Widget buildChip({BoxConstraints? avatarBoxConstraints}) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: Chip(
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
avatar: const Icon(Icons.favorite),
|
||||
label: Container(
|
||||
width: labelSize.width,
|
||||
height: labelSize.width,
|
||||
color: const Color(0xFFFF0000),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test default avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip());
|
||||
|
||||
expect(tester.getSize(find.byType(Chip)).width, equals(234.0));
|
||||
expect(tester.getSize(find.byType(Chip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
Offset chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
final Offset avatarCenter = tester.getCenter(find.byIcon(Icons.favorite));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (labelSize.width / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between avatar and label.
|
||||
Offset labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (labelSize.width / 2) + labelPadding);
|
||||
|
||||
// Test custom avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip(avatarBoxConstraints: const BoxConstraints.tightForFinite()));
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(find.byType(Chip)).width, equals(152.0));
|
||||
expect(tester.getSize(find.byType(Chip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (iconSize / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between avatar and label.
|
||||
labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (iconSize / 2) + labelPadding);
|
||||
});
|
||||
|
||||
testWidgets('RawChip avatar layout constraints can be customized', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double labelPadding = 8.0;
|
||||
const double padding = 8.0;
|
||||
const Size labelSize = Size(100, 100);
|
||||
|
||||
Widget buildChip({BoxConstraints? avatarBoxConstraints}) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: RawChip(
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
avatar: const Icon(Icons.favorite),
|
||||
label: Container(
|
||||
width: labelSize.width,
|
||||
height: labelSize.width,
|
||||
color: const Color(0xFFFF0000),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test default avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip());
|
||||
|
||||
expect(tester.getSize(find.byType(RawChip)).width, equals(234.0));
|
||||
expect(tester.getSize(find.byType(RawChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
Offset chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
final Offset avatarCenter = tester.getCenter(find.byIcon(Icons.favorite));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (labelSize.width / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between avatar and label.
|
||||
Offset labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (labelSize.width / 2) + labelPadding);
|
||||
|
||||
// Test custom avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip(avatarBoxConstraints: const BoxConstraints.tightForFinite()));
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(find.byType(RawChip)).width, equals(152.0));
|
||||
expect(tester.getSize(find.byType(RawChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (iconSize / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between avatar and label.
|
||||
labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (iconSize / 2) + labelPadding);
|
||||
});
|
||||
|
||||
testWidgets('Chip delete icon layout constraints can be customized', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double labelPadding = 8.0;
|
||||
const double padding = 8.0;
|
||||
const Size labelSize = Size(100, 100);
|
||||
|
||||
Widget buildChip({BoxConstraints? deleteIconBoxConstraints}) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: Chip(
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||
onDeleted: () { },
|
||||
label: Container(
|
||||
width: labelSize.width,
|
||||
height: labelSize.width,
|
||||
color: const Color(0xFFFF0000),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test default delete icon layout constraints.
|
||||
await tester.pumpWidget(buildChip());
|
||||
|
||||
expect(tester.getSize(find.byType(Chip)).width, equals(234.0));
|
||||
expect(tester.getSize(find.byType(Chip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between delete icon and chip edges.
|
||||
Offset chipTopRight = tester.getTopRight(find.byWidget(getMaterial(tester)));
|
||||
final Offset deleteIconCenter = tester.getCenter(find.byIcon(Icons.cancel));
|
||||
expect(chipTopRight.dx, deleteIconCenter.dx + (labelSize.width / 2) + padding + border);
|
||||
expect(chipTopRight.dy, deleteIconCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between delete icon and label.
|
||||
Offset labelTopRight = tester.getTopRight(find.byType(Container));
|
||||
expect(labelTopRight.dx, deleteIconCenter.dx - (labelSize.width / 2) - labelPadding);
|
||||
|
||||
// Test custom avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip(
|
||||
deleteIconBoxConstraints: const BoxConstraints.tightForFinite(),
|
||||
));
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(find.byType(Chip)).width, equals(152.0));
|
||||
expect(tester.getSize(find.byType(Chip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between delete icon and chip edges.
|
||||
chipTopRight = tester.getTopRight(find.byWidget(getMaterial(tester)));
|
||||
expect(chipTopRight.dx, deleteIconCenter.dx + (iconSize / 2) + padding + border);
|
||||
expect(chipTopRight.dy, deleteIconCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between delete icon and label.
|
||||
labelTopRight = tester.getTopRight(find.byType(Container));
|
||||
expect(labelTopRight.dx, deleteIconCenter.dx - (iconSize / 2) - labelPadding);
|
||||
});
|
||||
|
||||
testWidgets('RawChip delete icon layout constraints can be customized', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double labelPadding = 8.0;
|
||||
const double padding = 8.0;
|
||||
const Size labelSize = Size(100, 100);
|
||||
|
||||
Widget buildChip({BoxConstraints? deleteIconBoxConstraints}) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: RawChip(
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||
onDeleted: () { },
|
||||
label: Container(
|
||||
width: labelSize.width,
|
||||
height: labelSize.width,
|
||||
color: const Color(0xFFFF0000),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test default delete icon layout constraints.
|
||||
await tester.pumpWidget(buildChip());
|
||||
|
||||
expect(tester.getSize(find.byType(RawChip)).width, equals(234.0));
|
||||
expect(tester.getSize(find.byType(RawChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between delete icon and chip edges.
|
||||
Offset chipTopRight = tester.getTopRight(find.byWidget(getMaterial(tester)));
|
||||
final Offset deleteIconCenter = tester.getCenter(find.byIcon(Icons.cancel));
|
||||
expect(chipTopRight.dx, deleteIconCenter.dx + (labelSize.width / 2) + padding + border);
|
||||
expect(chipTopRight.dy, deleteIconCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between delete icon and label.
|
||||
Offset labelTopRight = tester.getTopRight(find.byType(Container));
|
||||
expect(labelTopRight.dx, deleteIconCenter.dx - (labelSize.width / 2) - labelPadding);
|
||||
|
||||
// Test custom avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip(
|
||||
deleteIconBoxConstraints: const BoxConstraints.tightForFinite(),
|
||||
));
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(find.byType(RawChip)).width, equals(152.0));
|
||||
expect(tester.getSize(find.byType(RawChip )).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between delete icon and chip edges.
|
||||
chipTopRight = tester.getTopRight(find.byWidget(getMaterial(tester)));
|
||||
expect(chipTopRight.dx, deleteIconCenter.dx + (iconSize / 2) + padding + border);
|
||||
expect(chipTopRight.dy, deleteIconCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between delete icon and label.
|
||||
labelTopRight = tester.getTopRight(find.byType(Container));
|
||||
expect(labelTopRight.dx, deleteIconCenter.dx - (iconSize / 2) - labelPadding);
|
||||
});
|
||||
|
||||
group('Material 2', () {
|
||||
// These tests are only relevant for Material 2. Once Material 2
|
||||
// support is deprecated and the APIs are removed, these tests
|
||||
|
|
|
@ -79,6 +79,8 @@ void main() {
|
|||
expect(themeData.elevation, null);
|
||||
expect(themeData.pressElevation, null);
|
||||
expect(themeData.iconTheme, null);
|
||||
expect(themeData.avatarBoxConstraints, null);
|
||||
expect(themeData.deleteIconBoxConstraints, null);
|
||||
});
|
||||
|
||||
testWidgets('Default ChipThemeData debugFillProperties', (WidgetTester tester) async {
|
||||
|
@ -117,6 +119,8 @@ void main() {
|
|||
elevation: 5,
|
||||
pressElevation: 6,
|
||||
iconTheme: IconThemeData(color: Color(0xffffff10)),
|
||||
avatarBoxConstraints: BoxConstraints.tightForFinite(),
|
||||
deleteIconBoxConstraints: BoxConstraints.tightForFinite(),
|
||||
).debugFillProperties(builder);
|
||||
|
||||
final List<String> description = builder.properties
|
||||
|
@ -145,7 +149,9 @@ void main() {
|
|||
'brightness: dark',
|
||||
'elevation: 5.0',
|
||||
'pressElevation: 6.0',
|
||||
'iconTheme: IconThemeData#00000(color: Color(0xffffff10))'
|
||||
'iconTheme: IconThemeData#00000(color: Color(0xffffff10))',
|
||||
'avatarBoxConstraints: BoxConstraints(unconstrained)',
|
||||
'deleteIconBoxConstraints: BoxConstraints(unconstrained)',
|
||||
]));
|
||||
});
|
||||
|
||||
|
@ -1314,6 +1320,86 @@ void main() {
|
|||
expect(getIconData(tester).size, 23.0);
|
||||
expect(getIconData(tester).color, const Color(0xff112233));
|
||||
});
|
||||
|
||||
testWidgets('ChipThemeData.avatarBoxConstraints updates avatar size constraints', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double labelPadding = 8.0;
|
||||
const double padding = 8.0;
|
||||
const Size labelSize = Size(75, 75);
|
||||
|
||||
// Test default avatar layout constraints.
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(chipTheme: const ChipThemeData(
|
||||
avatarBoxConstraints: BoxConstraints.tightForFinite(),
|
||||
)),
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: RawChip(
|
||||
avatar: const Icon(Icons.favorite),
|
||||
label: Container(
|
||||
width: labelSize.width,
|
||||
height: labelSize.width,
|
||||
color: const Color(0xFFFF0000),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
expect(tester.getSize(find.byType(RawChip)).width, equals(127.0));
|
||||
expect(tester.getSize(find.byType(RawChip)).height, equals(93.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
final Offset chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
final Offset avatarCenter = tester.getCenter(find.byIcon(Icons.favorite));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (iconSize / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between avatar and label.
|
||||
final Offset labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (iconSize / 2) + labelPadding);
|
||||
});
|
||||
|
||||
testWidgets('ChipThemeData.deleteIconBoxConstraints updates delete icon size constraints', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double labelPadding = 8.0;
|
||||
const double padding = 8.0;
|
||||
const Size labelSize = Size(75, 75);
|
||||
|
||||
// Test custom delete layout constraints.
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(chipTheme: const ChipThemeData(
|
||||
deleteIconBoxConstraints: BoxConstraints.tightForFinite(),
|
||||
)),
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: RawChip(
|
||||
onDeleted: () { },
|
||||
label: Container(
|
||||
width: labelSize.width,
|
||||
height: labelSize.width,
|
||||
color: const Color(0xFFFF0000),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
expect(tester.getSize(find.byType(RawChip)).width, equals(127.0));
|
||||
expect(tester.getSize(find.byType(RawChip)).height, equals(93.0));
|
||||
|
||||
// Calculate the distance between delete icon and chip edges.
|
||||
final Offset chipTopRight = tester.getTopRight(find.byWidget(getMaterial(tester)));
|
||||
final Offset deleteIconCenter = tester.getCenter(find.byIcon(Icons.cancel));
|
||||
expect(chipTopRight.dx, deleteIconCenter.dx + (iconSize / 2) + padding + border);
|
||||
expect(chipTopRight.dy, deleteIconCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between delete icon and label.
|
||||
final Offset labelTopRight = tester.getTopRight(find.byType(Container));
|
||||
expect(labelTopRight.dx, deleteIconCenter.dx - (iconSize / 2) - labelPadding);
|
||||
});
|
||||
}
|
||||
|
||||
class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder {
|
||||
|
|
|
@ -718,4 +718,61 @@ void main() {
|
|||
|
||||
expect(getIconData(tester).color, const Color(0xff00ff00));
|
||||
});
|
||||
|
||||
testWidgets('ChoiceChip avatar layout constraints can be customized', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double labelPadding = 8.0;
|
||||
const double padding = 8.0;
|
||||
const Size labelSize = Size(100, 100);
|
||||
|
||||
Widget buildChip({BoxConstraints? avatarBoxConstraints}) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: ChoiceChip(
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
avatar: const Icon(Icons.favorite),
|
||||
label: Container(
|
||||
width: labelSize.width,
|
||||
height: labelSize.width,
|
||||
color: const Color(0xFFFF0000),
|
||||
),
|
||||
selected: false,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test default avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip());
|
||||
|
||||
expect(tester.getSize(find.byType(ChoiceChip)).width, equals(234.0));
|
||||
expect(tester.getSize(find.byType(ChoiceChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
Offset chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
final Offset avatarCenter = tester.getCenter(find.byIcon(Icons.favorite));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (labelSize.width / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between avatar and label.
|
||||
Offset labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (labelSize.width / 2) + labelPadding);
|
||||
|
||||
// Test custom avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip(avatarBoxConstraints: const BoxConstraints.tightForFinite()));
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(find.byType(ChoiceChip)).width, equals(152.0));
|
||||
expect(tester.getSize(find.byType(ChoiceChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (iconSize / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between avatar and label.
|
||||
labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (iconSize / 2) + labelPadding);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1170,4 +1170,120 @@ void main() {
|
|||
theme.colorScheme.onSecondaryContainer,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('FilterChip avatar layout constraints can be customized', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double labelPadding = 8.0;
|
||||
const double padding = 8.0;
|
||||
const Size labelSize = Size(100, 100);
|
||||
|
||||
Widget buildChip({BoxConstraints? avatarBoxConstraints}) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: FilterChip(
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
avatar: const Icon(Icons.favorite),
|
||||
label: Container(
|
||||
width: labelSize.width,
|
||||
height: labelSize.width,
|
||||
color: const Color(0xFFFF0000),
|
||||
),
|
||||
onSelected: (bool value) { },
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test default avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip());
|
||||
|
||||
expect(tester.getSize(find.byType(FilterChip)).width, equals(234.0));
|
||||
expect(tester.getSize(find.byType(FilterChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
Offset chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
final Offset avatarCenter = tester.getCenter(find.byIcon(Icons.favorite));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (labelSize.width / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distnance between avatar and label.
|
||||
Offset labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (labelSize.width / 2) + labelPadding);
|
||||
|
||||
// Test custom avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip(avatarBoxConstraints: const BoxConstraints.tightForFinite()));
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(find.byType(FilterChip)).width, equals(152.0));
|
||||
expect(tester.getSize(find.byType(FilterChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (iconSize / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distnance between avatar and label.
|
||||
labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (iconSize / 2) + labelPadding);
|
||||
});
|
||||
|
||||
testWidgets('FilterChip delete icon layout constraints can be customized', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double labelPadding = 8.0;
|
||||
const double padding = 8.0;
|
||||
const Size labelSize = Size(100, 100);
|
||||
|
||||
Widget buildChip({BoxConstraints? deleteIconBoxConstraints}) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: FilterChip(
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||
onDeleted: () { },
|
||||
label: Container(
|
||||
width: labelSize.width,
|
||||
height: labelSize.width,
|
||||
color: const Color(0xFFFF0000),
|
||||
),
|
||||
onSelected: (bool value) { },
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test default delete icon layout constraints.
|
||||
await tester.pumpWidget(buildChip());
|
||||
|
||||
expect(tester.getSize(find.byType(FilterChip)).width, equals(234.0));
|
||||
expect(tester.getSize(find.byType(FilterChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between delete icon and chip edges.
|
||||
Offset chipTopRight = tester.getTopRight(find.byWidget(getMaterial(tester)));
|
||||
final Offset deleteIconCenter = tester.getCenter(find.byIcon(Icons.clear));
|
||||
expect(chipTopRight.dx, deleteIconCenter.dx + (labelSize.width / 2) + padding + border);
|
||||
expect(chipTopRight.dy, deleteIconCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between delete icon and label.
|
||||
Offset labelTopRight = tester.getTopRight(find.byType(Container));
|
||||
expect(labelTopRight.dx, deleteIconCenter.dx - (labelSize.width / 2) - labelPadding);
|
||||
|
||||
// Test custom avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip(
|
||||
deleteIconBoxConstraints: const BoxConstraints.tightForFinite(),
|
||||
));
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(find.byType(FilterChip)).width, equals(152.0));
|
||||
expect(tester.getSize(find.byType(FilterChip )).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between delete icon and chip edges.
|
||||
chipTopRight = tester.getTopRight(find.byWidget(getMaterial(tester)));
|
||||
expect(chipTopRight.dx, deleteIconCenter.dx + (iconSize / 2) + padding + border);
|
||||
expect(chipTopRight.dy, deleteIconCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between delete icon and label.
|
||||
labelTopRight = tester.getTopRight(find.byType(Container));
|
||||
expect(labelTopRight.dx, deleteIconCenter.dx - (iconSize / 2) - labelPadding);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -97,6 +97,15 @@ RenderBox getMaterialBox(WidgetTester tester) {
|
|||
);
|
||||
}
|
||||
|
||||
Material getMaterial(WidgetTester tester) {
|
||||
return tester.widget<Material>(
|
||||
find.descendant(
|
||||
of: find.byType(InputChip),
|
||||
matching: find.byType(Material),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
IconThemeData getIconData(WidgetTester tester) {
|
||||
final IconTheme iconTheme = tester.firstWidget(
|
||||
find.descendant(
|
||||
|
@ -476,4 +485,118 @@ void main() {
|
|||
// Delete button tooltip should not be visible.
|
||||
expect(findTooltipContainer('Delete'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('InputChip avatar layout constraints can be customized', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double labelPadding = 8.0;
|
||||
const double padding = 8.0;
|
||||
const Size labelSize = Size(100, 100);
|
||||
|
||||
Widget buildChip({BoxConstraints? avatarBoxConstraints}) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: InputChip(
|
||||
avatarBoxConstraints: avatarBoxConstraints,
|
||||
avatar: const Icon(Icons.favorite),
|
||||
label: Container(
|
||||
width: labelSize.width,
|
||||
height: labelSize.width,
|
||||
color: const Color(0xFFFF0000),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test default avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip());
|
||||
|
||||
expect(tester.getSize(find.byType(InputChip)).width, equals(234.0));
|
||||
expect(tester.getSize(find.byType(InputChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
Offset chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
final Offset avatarCenter = tester.getCenter(find.byIcon(Icons.favorite));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (labelSize.width / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distnance between avatar and label.
|
||||
Offset labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (labelSize.width / 2) + labelPadding);
|
||||
|
||||
// Test custom avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip(avatarBoxConstraints: const BoxConstraints.tightForFinite()));
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(find.byType(InputChip)).width, equals(152.0));
|
||||
expect(tester.getSize(find.byType(InputChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between avatar and chip edges.
|
||||
chipTopLeft = tester.getTopLeft(find.byWidget(getMaterial(tester)));
|
||||
expect(chipTopLeft.dx, avatarCenter.dx - (iconSize / 2) - padding - border);
|
||||
expect(chipTopLeft.dy, avatarCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distnance between avatar and label.
|
||||
labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||
expect(labelTopLeft.dx, avatarCenter.dx + (iconSize / 2) + labelPadding);
|
||||
});
|
||||
|
||||
testWidgets('InputChip delete icon layout constraints can be customized', (WidgetTester tester) async {
|
||||
const double border = 1.0;
|
||||
const double iconSize = 18.0;
|
||||
const double labelPadding = 8.0;
|
||||
const double padding = 8.0;
|
||||
const Size labelSize = Size(100, 100);
|
||||
|
||||
Widget buildChip({BoxConstraints? deleteIconBoxConstraints}) {
|
||||
return wrapForChip(
|
||||
child: Center(
|
||||
child: InputChip(
|
||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||
onDeleted: () { },
|
||||
label: Container(
|
||||
width: labelSize.width,
|
||||
height: labelSize.width,
|
||||
color: const Color(0xFFFF0000),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test default delete icon layout constraints.
|
||||
await tester.pumpWidget(buildChip());
|
||||
|
||||
expect(tester.getSize(find.byType(InputChip)).width, equals(234.0));
|
||||
expect(tester.getSize(find.byType(InputChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between delete icon and chip edges.
|
||||
Offset chipTopRight = tester.getTopRight(find.byWidget(getMaterial(tester)));
|
||||
final Offset deleteIconCenter = tester.getCenter(find.byIcon(Icons.clear));
|
||||
expect(chipTopRight.dx, deleteIconCenter.dx + (labelSize.width / 2) + padding + border);
|
||||
expect(chipTopRight.dy, deleteIconCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between delete icon and label.
|
||||
Offset labelTopRight = tester.getTopRight(find.byType(Container));
|
||||
expect(labelTopRight.dx, deleteIconCenter.dx - (labelSize.width / 2) - labelPadding);
|
||||
|
||||
// Test custom avatar layout constraints.
|
||||
await tester.pumpWidget(buildChip(
|
||||
deleteIconBoxConstraints: const BoxConstraints.tightForFinite(),
|
||||
));
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.getSize(find.byType(InputChip)).width, equals(152.0));
|
||||
expect(tester.getSize(find.byType(InputChip)).height, equals(118.0));
|
||||
|
||||
// Calculate the distance between delete icon and chip edges.
|
||||
chipTopRight = tester.getTopRight(find.byWidget(getMaterial(tester)));
|
||||
expect(chipTopRight.dx, deleteIconCenter.dx + (iconSize / 2) + padding + border);
|
||||
expect(chipTopRight.dy, deleteIconCenter.dy - (labelSize.width / 2) - padding - border);
|
||||
|
||||
// Calculate the distance between delete icon and label.
|
||||
labelTopRight = tester.getTopRight(find.byType(Container));
|
||||
expect(labelTopRight.dx, deleteIconCenter.dx - (iconSize / 2) - labelPadding);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue