Skip to content

Commit

Permalink
Introduce avatarBoxConstraints & deleteIconBoxConstraints for the…
Browse files Browse the repository at this point in the history
… chips (#143302)

fixes [Chip widget's avatar padding changing if label text is more than 1 line](flutter/flutter#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)
  • Loading branch information
TahaTesser authored Feb 13, 2024
1 parent a8e9f20 commit ccf42dd
Show file tree
Hide file tree
Showing 16 changed files with 1,079 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -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,
),
),
),
],
);
}
}
Original file line number Diff line number Diff line change
@@ -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,
),
),
),
],
);
}
}
Original file line number Diff line number Diff line change
@@ -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);
});
}
Original file line number Diff line number Diff line change
@@ -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);
});
}
5 changes: 5 additions & 0 deletions packages/flutter/lib/src/material/action_chip.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -228,6 +232,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
shadowColor: shadowColor,
surfaceTintColor: surfaceTintColor,
iconTheme: iconTheme,
avatarBoxConstraints: avatarBoxConstraints,
);
}
}
Expand Down
Loading

0 comments on commit ccf42dd

Please sign in to comment.