[Reland] Introduce ChipAnimationStyle
to override default chips animations durations (#149876)
Reland - https://github.com/flutter/flutter/pull/149245 --- fixes [Custom backgroundColor on Chip makes it flicker between state transitions](https://github.com/flutter/flutter/issues/146730) ### Example preview  https://github.com/flutter/flutter/assets/48603081/a4949ce7-f38b-4251-8201-ecc570ec447c
This commit is contained in:
parent
15af844c02
commit
f56e0c2845
@ -0,0 +1,164 @@
|
|||||||
|
// 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.chipAnimationStyle].
|
||||||
|
|
||||||
|
void main() => runApp(const ChipAnimationStyleExampleApp());
|
||||||
|
|
||||||
|
class ChipAnimationStyleExampleApp extends StatelessWidget {
|
||||||
|
const ChipAnimationStyleExampleApp({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: Center(
|
||||||
|
child: ChipAnimationStyleExample(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChipAnimationStyleExample extends StatefulWidget {
|
||||||
|
const ChipAnimationStyleExample({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ChipAnimationStyleExample> createState() =>
|
||||||
|
_ChipAnimationStyleExampleState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ChipAnimationStyleExampleState extends State<ChipAnimationStyleExample> {
|
||||||
|
bool enabled = true;
|
||||||
|
bool selected = false;
|
||||||
|
bool showCheckmark = true;
|
||||||
|
bool showDeleteIcon = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: <Widget>[
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: <Widget>[
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
FilterChip.elevated(
|
||||||
|
chipAnimationStyle: ChipAnimationStyle(
|
||||||
|
enableAnimation: AnimationStyle(
|
||||||
|
duration: const Duration(seconds: 3),
|
||||||
|
reverseDuration: const Duration(seconds: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onSelected: !enabled ? null : (bool value) {},
|
||||||
|
disabledColor: Colors.red.withOpacity(0.12),
|
||||||
|
backgroundColor: Colors.amber,
|
||||||
|
label: Text(enabled ? 'Enabled' : 'Disabled'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
enabled = !enabled;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text(enabled ? 'Disable' : 'Enable'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
FilterChip.elevated(
|
||||||
|
chipAnimationStyle: ChipAnimationStyle(
|
||||||
|
selectAnimation: AnimationStyle(
|
||||||
|
duration: const Duration(seconds: 3),
|
||||||
|
reverseDuration: const Duration(seconds: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.amber,
|
||||||
|
selectedColor: Colors.blue,
|
||||||
|
selected: selected,
|
||||||
|
showCheckmark: false,
|
||||||
|
onSelected: (bool value) {},
|
||||||
|
label: Text(selected ? 'Selected' : 'Unselected'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
selected = !selected;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text(selected ? 'Unselect' : 'Select'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: <Widget>[
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
FilterChip.elevated(
|
||||||
|
chipAnimationStyle: ChipAnimationStyle(
|
||||||
|
avatarDrawerAnimation: AnimationStyle(
|
||||||
|
duration: const Duration(seconds: 2),
|
||||||
|
reverseDuration: const Duration(seconds: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
selected: showCheckmark,
|
||||||
|
onSelected: (bool value) {},
|
||||||
|
label: Text(showCheckmark ? 'Checked' : 'Unchecked'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
showCheckmark = !showCheckmark;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child:
|
||||||
|
Text(showCheckmark ? 'Hide checkmark' : 'Show checkmark'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
FilterChip.elevated(
|
||||||
|
chipAnimationStyle: ChipAnimationStyle(
|
||||||
|
deleteDrawerAnimation: AnimationStyle(
|
||||||
|
duration: const Duration(seconds: 2),
|
||||||
|
reverseDuration: const Duration(seconds: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onDeleted: showDeleteIcon ? () {} : null,
|
||||||
|
onSelected: (bool value) {},
|
||||||
|
label: Text(showDeleteIcon ? 'Deletable' : 'Undeletable'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
showDeleteIcon = !showDeleteIcon;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
showDeleteIcon ? 'Hide delete icon' : 'Show delete icon'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,135 @@
|
|||||||
|
// 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.chip_animation_style.0.dart' as example;
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('ChipAnimationStyle.enableAnimation overrides chip enable animation', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const example.ChipAnimationStyleExampleApp(),
|
||||||
|
);
|
||||||
|
|
||||||
|
final RenderBox materialBox = tester.firstRenderObject<RenderBox>(
|
||||||
|
find.descendant(
|
||||||
|
of: find.widgetWithText(RawChip, 'Enabled'),
|
||||||
|
matching: find.byType(CustomPaint),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0xffffc107)));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Disable'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 500)); // Advance enable animation by 500ms.
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0x1f882f2b)));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 500)); // Advance enable animation by 500ms.
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0x1ff44336)));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Enable'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 1500)); // Advance enable animation by 1500ms.
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0xfffbd980)));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 1500)); // Advance enable animation by 1500ms.
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0xffffc107)));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('ChipAnimationStyle.selectAnimation overrides chip select animation', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const example.ChipAnimationStyleExampleApp(),
|
||||||
|
);
|
||||||
|
|
||||||
|
final RenderBox materialBox = tester.firstRenderObject<RenderBox>(
|
||||||
|
find.descendant(
|
||||||
|
of: find.widgetWithText(RawChip, 'Unselected'),
|
||||||
|
matching: find.byType(CustomPaint),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0xffffc107)));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Select'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 1500)); // Advance select animation by 1500ms.
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0xff4da6f4)));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 1500)); // Advance select animation by 1500ms.
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0xff2196f3)));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Unselect'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 500)); // Advance select animation by 500ms.
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0xfff8e7c3)));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 500)); // Advance select animation by 500ms.
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0xffffc107)));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('ChipAnimationStyle.avatarDrawerAnimation overrides chip checkmark animation', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const example.ChipAnimationStyleExampleApp(),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(tester.getSize(find.widgetWithText(RawChip, 'Checked')).width, closeTo(152.6, 0.1));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Hide checkmark'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 500)); // Advance avatar animation by 500ms.
|
||||||
|
|
||||||
|
expect(tester.getSize(find.widgetWithText(RawChip, 'Unchecked')).width, closeTo(160.9, 0.1));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 500)); // Advance avatar animation by 500ms.
|
||||||
|
|
||||||
|
expect(tester.getSize(find.widgetWithText(RawChip, 'Unchecked')).width, closeTo(160.9, 0.1));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Show checkmark'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(seconds: 1)); // Advance avatar animation by 1sec.
|
||||||
|
|
||||||
|
expect(tester.getSize(find.widgetWithText(RawChip, 'Checked')).width, closeTo(132.7, 0.1));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(seconds: 1)); // Advance avatar animation by 1sec.
|
||||||
|
|
||||||
|
expect(tester.getSize(find.widgetWithText(RawChip, 'Checked')).width, closeTo(152.6, 0.1));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('ChipAnimationStyle.deleteDrawerAnimation overrides chip delete icon animation', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const example.ChipAnimationStyleExampleApp(),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(tester.getSize(find.widgetWithText(RawChip, 'Deletable')).width, closeTo(180.9, 0.1));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Hide delete icon'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 500)); // Advance delete icon animation by 500ms.
|
||||||
|
|
||||||
|
expect(tester.getSize(find.widgetWithText(RawChip, 'Undeletable')).width, closeTo(204.6, 0.1));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 500)); // Advance delete icon animation by 500ms.
|
||||||
|
|
||||||
|
expect(tester.getSize(find.widgetWithText(RawChip, 'Undeletable')).width, closeTo(189.1, 0.1));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Show delete icon'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(seconds: 1)); // Advance delete icon animation by 1sec.
|
||||||
|
|
||||||
|
expect(tester.getSize(find.widgetWithText(RawChip, 'Deletable')).width, closeTo(176.4, 0.1));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(seconds: 1)); // Advance delete icon animation by 1sec.
|
||||||
|
|
||||||
|
expect(tester.getSize(find.widgetWithText(RawChip, 'Deletable')).width, closeTo(180.9, 0.1));
|
||||||
|
});
|
||||||
|
}
|
@ -110,6 +110,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||||||
this.surfaceTintColor,
|
this.surfaceTintColor,
|
||||||
this.iconTheme,
|
this.iconTheme,
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
|
this.chipAnimationStyle,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
_chipVariant = _ChipVariant.flat;
|
_chipVariant = _ChipVariant.flat;
|
||||||
@ -145,6 +146,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||||||
this.surfaceTintColor,
|
this.surfaceTintColor,
|
||||||
this.iconTheme,
|
this.iconTheme,
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
|
this.chipAnimationStyle,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
_chipVariant = _ChipVariant.elevated;
|
_chipVariant = _ChipVariant.elevated;
|
||||||
@ -195,6 +197,8 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||||||
final IconThemeData? iconTheme;
|
final IconThemeData? iconTheme;
|
||||||
@override
|
@override
|
||||||
final BoxConstraints? avatarBoxConstraints;
|
final BoxConstraints? avatarBoxConstraints;
|
||||||
|
@override
|
||||||
|
final ChipAnimationStyle? chipAnimationStyle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isEnabled => onPressed != null;
|
bool get isEnabled => onPressed != null;
|
||||||
@ -233,6 +237,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
|
|||||||
surfaceTintColor: surfaceTintColor,
|
surfaceTintColor: surfaceTintColor,
|
||||||
iconTheme: iconTheme,
|
iconTheme: iconTheme,
|
||||||
avatarBoxConstraints: avatarBoxConstraints,
|
avatarBoxConstraints: avatarBoxConstraints,
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,6 +243,32 @@ abstract interface class ChipAttributes {
|
|||||||
/// ** See code in examples/api/lib/material/chip/chip_attributes.avatar_box_constraints.0.dart **
|
/// ** See code in examples/api/lib/material/chip/chip_attributes.avatar_box_constraints.0.dart **
|
||||||
/// {@end-tool}
|
/// {@end-tool}
|
||||||
BoxConstraints? get avatarBoxConstraints;
|
BoxConstraints? get avatarBoxConstraints;
|
||||||
|
|
||||||
|
/// Used to override the default chip animations durations.
|
||||||
|
///
|
||||||
|
/// If [ChipAnimationStyle.enableAnimation] with duration or reverse duration is
|
||||||
|
/// provided, it will be used to override the chip enable and disable animation durations.
|
||||||
|
/// If it is null, then default duration will be 75ms.
|
||||||
|
///
|
||||||
|
/// If [ChipAnimationStyle.selectAnimation] with duration or reverse duration is provided,
|
||||||
|
/// it will be used to override the chip select and unselect animation durations.
|
||||||
|
/// If it is null, then default duration will be 195ms.
|
||||||
|
///
|
||||||
|
/// If [ChipAnimationStyle.avatarDrawerAnimation] with duration or reverse duration
|
||||||
|
/// is provided, it will be used to override the chip checkmark animation duration.
|
||||||
|
/// If it is null, then default duration will be 150ms.
|
||||||
|
///
|
||||||
|
/// If [ChipAnimationStyle.deleteDrawerAnimation] with duration or reverse duration
|
||||||
|
/// is provided, it will be used to override the chip delete icon animation duration.
|
||||||
|
/// If it is null, then default duration will be 150ms.
|
||||||
|
///
|
||||||
|
/// {@tool dartpad}
|
||||||
|
/// This sample showcases how to override the chip animations durations using
|
||||||
|
/// [ChipAnimationStyle].
|
||||||
|
///
|
||||||
|
/// ** See code in examples/api/lib/material/chip/chip_attributes.chip_animation_style.0.dart **
|
||||||
|
/// {@end-tool}
|
||||||
|
ChipAnimationStyle? get chipAnimationStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An interface for Material Design chips that can be deleted.
|
/// An interface for Material Design chips that can be deleted.
|
||||||
@ -568,6 +594,37 @@ abstract interface class TappableChipAttributes {
|
|||||||
String? get tooltip;
|
String? get tooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A helper class that overrides the default chip animation parameters.
|
||||||
|
class ChipAnimationStyle {
|
||||||
|
/// Creates an instance of Chip Animation Style class.
|
||||||
|
ChipAnimationStyle({
|
||||||
|
this.enableAnimation,
|
||||||
|
this.selectAnimation,
|
||||||
|
this.avatarDrawerAnimation,
|
||||||
|
this.deleteDrawerAnimation,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// If [enableAnimation] with duration or reverse duration is provided,
|
||||||
|
/// it will be used to override the chip enable and disable animation durations.
|
||||||
|
/// If it is null, then default duration will be 75ms.
|
||||||
|
final AnimationStyle? enableAnimation;
|
||||||
|
|
||||||
|
/// If [selectAnimation] with duration or reverse duration is provided,
|
||||||
|
/// it will be used to override the chip select and unselect animation durations.
|
||||||
|
/// If it is null, then default duration will be 195ms.
|
||||||
|
final AnimationStyle? selectAnimation;
|
||||||
|
|
||||||
|
/// If [avatarDrawerAnimation] with duration or reverse duration is provided,
|
||||||
|
/// it will be used to override the chip checkmark animation duration. If it
|
||||||
|
/// is null, then default duration will be 150ms.
|
||||||
|
final AnimationStyle? avatarDrawerAnimation;
|
||||||
|
|
||||||
|
/// If [deleteDrawerAnimation] with duration or reverse duration is provided,
|
||||||
|
/// it will be used to override the chip delete icon animation duration. If it
|
||||||
|
/// is null, then default duration will be 150ms.
|
||||||
|
final AnimationStyle? deleteDrawerAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
/// A Material Design chip.
|
/// A Material Design chip.
|
||||||
///
|
///
|
||||||
/// Chips are compact elements that represent an attribute, text, entity, or
|
/// Chips are compact elements that represent an attribute, text, entity, or
|
||||||
@ -637,6 +694,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
|||||||
this.iconTheme,
|
this.iconTheme,
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.deleteIconBoxConstraints,
|
this.deleteIconBoxConstraints,
|
||||||
|
this.chipAnimationStyle,
|
||||||
}) : assert(elevation == null || elevation >= 0.0);
|
}) : assert(elevation == null || elevation >= 0.0);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -687,6 +745,8 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
|||||||
final BoxConstraints? avatarBoxConstraints;
|
final BoxConstraints? avatarBoxConstraints;
|
||||||
@override
|
@override
|
||||||
final BoxConstraints? deleteIconBoxConstraints;
|
final BoxConstraints? deleteIconBoxConstraints;
|
||||||
|
@override
|
||||||
|
final ChipAnimationStyle? chipAnimationStyle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -717,6 +777,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
|||||||
iconTheme: iconTheme,
|
iconTheme: iconTheme,
|
||||||
avatarBoxConstraints: avatarBoxConstraints,
|
avatarBoxConstraints: avatarBoxConstraints,
|
||||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -806,6 +867,7 @@ class RawChip extends StatefulWidget
|
|||||||
this.avatarBorder = const CircleBorder(),
|
this.avatarBorder = const CircleBorder(),
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.deleteIconBoxConstraints,
|
this.deleteIconBoxConstraints,
|
||||||
|
this.chipAnimationStyle,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
deleteIcon = deleteIcon ?? _kDefaultDeleteIcon;
|
deleteIcon = deleteIcon ?? _kDefaultDeleteIcon;
|
||||||
@ -889,6 +951,8 @@ class RawChip extends StatefulWidget
|
|||||||
final BoxConstraints? avatarBoxConstraints;
|
final BoxConstraints? avatarBoxConstraints;
|
||||||
@override
|
@override
|
||||||
final BoxConstraints? deleteIconBoxConstraints;
|
final BoxConstraints? deleteIconBoxConstraints;
|
||||||
|
@override
|
||||||
|
final ChipAnimationStyle? chipAnimationStyle;
|
||||||
|
|
||||||
/// If set, this indicates that the chip should be disabled if all of the
|
/// If set, this indicates that the chip should be disabled if all of the
|
||||||
/// tap callbacks ([onSelected], [onPressed]) are null.
|
/// tap callbacks ([onSelected], [onPressed]) are null.
|
||||||
@ -936,7 +1000,8 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
|
|||||||
setMaterialState(MaterialState.disabled, !widget.isEnabled);
|
setMaterialState(MaterialState.disabled, !widget.isEnabled);
|
||||||
setMaterialState(MaterialState.selected, widget.selected);
|
setMaterialState(MaterialState.selected, widget.selected);
|
||||||
selectController = AnimationController(
|
selectController = AnimationController(
|
||||||
duration: _kSelectDuration,
|
duration: widget.chipAnimationStyle?.selectAnimation?.duration ?? _kSelectDuration,
|
||||||
|
reverseDuration: widget.chipAnimationStyle?.selectAnimation?.reverseDuration,
|
||||||
value: widget.selected ? 1.0 : 0.0,
|
value: widget.selected ? 1.0 : 0.0,
|
||||||
vsync: this,
|
vsync: this,
|
||||||
);
|
);
|
||||||
@ -945,17 +1010,20 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
|
|||||||
curve: Curves.fastOutSlowIn,
|
curve: Curves.fastOutSlowIn,
|
||||||
);
|
);
|
||||||
avatarDrawerController = AnimationController(
|
avatarDrawerController = AnimationController(
|
||||||
duration: _kDrawerDuration,
|
duration: widget.chipAnimationStyle?.avatarDrawerAnimation?.duration ?? _kDrawerDuration,
|
||||||
|
reverseDuration: widget.chipAnimationStyle?.avatarDrawerAnimation?.reverseDuration,
|
||||||
value: hasAvatar || widget.selected ? 1.0 : 0.0,
|
value: hasAvatar || widget.selected ? 1.0 : 0.0,
|
||||||
vsync: this,
|
vsync: this,
|
||||||
);
|
);
|
||||||
deleteDrawerController = AnimationController(
|
deleteDrawerController = AnimationController(
|
||||||
duration: _kDrawerDuration,
|
duration: widget.chipAnimationStyle?.deleteDrawerAnimation?.duration ?? _kDrawerDuration,
|
||||||
|
reverseDuration: widget.chipAnimationStyle?.deleteDrawerAnimation?.reverseDuration,
|
||||||
value: hasDeleteButton ? 1.0 : 0.0,
|
value: hasDeleteButton ? 1.0 : 0.0,
|
||||||
vsync: this,
|
vsync: this,
|
||||||
);
|
);
|
||||||
enableController = AnimationController(
|
enableController = AnimationController(
|
||||||
duration: _kDisableDuration,
|
duration: widget.chipAnimationStyle?.enableAnimation?.duration ?? _kDisableDuration,
|
||||||
|
reverseDuration: widget.chipAnimationStyle?.enableAnimation?.reverseDuration,
|
||||||
value: widget.isEnabled ? 1.0 : 0.0,
|
value: widget.isEnabled ? 1.0 : 0.0,
|
||||||
vsync: this,
|
vsync: this,
|
||||||
);
|
);
|
||||||
|
@ -93,6 +93,7 @@ class ChoiceChip extends StatelessWidget
|
|||||||
this.checkmarkColor,
|
this.checkmarkColor,
|
||||||
this.avatarBorder = const CircleBorder(),
|
this.avatarBorder = const CircleBorder(),
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
|
this.chipAnimationStyle,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
_chipVariant = _ChipVariant.flat;
|
_chipVariant = _ChipVariant.flat;
|
||||||
@ -134,6 +135,7 @@ class ChoiceChip extends StatelessWidget
|
|||||||
this.checkmarkColor,
|
this.checkmarkColor,
|
||||||
this.avatarBorder = const CircleBorder(),
|
this.avatarBorder = const CircleBorder(),
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
|
this.chipAnimationStyle,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
_chipVariant = _ChipVariant.elevated;
|
_chipVariant = _ChipVariant.elevated;
|
||||||
@ -196,6 +198,8 @@ class ChoiceChip extends StatelessWidget
|
|||||||
final IconThemeData? iconTheme;
|
final IconThemeData? iconTheme;
|
||||||
@override
|
@override
|
||||||
final BoxConstraints? avatarBoxConstraints;
|
final BoxConstraints? avatarBoxConstraints;
|
||||||
|
@override
|
||||||
|
final ChipAnimationStyle? chipAnimationStyle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isEnabled => onSelected != null;
|
bool get isEnabled => onSelected != null;
|
||||||
@ -241,6 +245,7 @@ class ChoiceChip extends StatelessWidget
|
|||||||
avatarBorder: avatarBorder,
|
avatarBorder: avatarBorder,
|
||||||
iconTheme: iconTheme,
|
iconTheme: iconTheme,
|
||||||
avatarBoxConstraints: avatarBoxConstraints,
|
avatarBoxConstraints: avatarBoxConstraints,
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,7 @@ class FilterChip extends StatelessWidget
|
|||||||
this.avatarBorder = const CircleBorder(),
|
this.avatarBorder = const CircleBorder(),
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.deleteIconBoxConstraints,
|
this.deleteIconBoxConstraints,
|
||||||
|
this.chipAnimationStyle,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
_chipVariant = _ChipVariant.flat;
|
_chipVariant = _ChipVariant.flat;
|
||||||
@ -149,6 +150,7 @@ class FilterChip extends StatelessWidget
|
|||||||
this.avatarBorder = const CircleBorder(),
|
this.avatarBorder = const CircleBorder(),
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.deleteIconBoxConstraints,
|
this.deleteIconBoxConstraints,
|
||||||
|
this.chipAnimationStyle,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0),
|
assert(elevation == null || elevation >= 0.0),
|
||||||
_chipVariant = _ChipVariant.elevated;
|
_chipVariant = _ChipVariant.elevated;
|
||||||
@ -221,6 +223,8 @@ class FilterChip extends StatelessWidget
|
|||||||
final BoxConstraints? avatarBoxConstraints;
|
final BoxConstraints? avatarBoxConstraints;
|
||||||
@override
|
@override
|
||||||
final BoxConstraints? deleteIconBoxConstraints;
|
final BoxConstraints? deleteIconBoxConstraints;
|
||||||
|
@override
|
||||||
|
final ChipAnimationStyle? chipAnimationStyle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isEnabled => onSelected != null;
|
bool get isEnabled => onSelected != null;
|
||||||
@ -272,6 +276,7 @@ class FilterChip extends StatelessWidget
|
|||||||
iconTheme: iconTheme,
|
iconTheme: iconTheme,
|
||||||
avatarBoxConstraints: avatarBoxConstraints,
|
avatarBoxConstraints: avatarBoxConstraints,
|
||||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,7 @@ class InputChip extends StatelessWidget
|
|||||||
this.avatarBorder = const CircleBorder(),
|
this.avatarBorder = const CircleBorder(),
|
||||||
this.avatarBoxConstraints,
|
this.avatarBoxConstraints,
|
||||||
this.deleteIconBoxConstraints,
|
this.deleteIconBoxConstraints,
|
||||||
|
this.chipAnimationStyle,
|
||||||
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
}) : assert(pressElevation == null || pressElevation >= 0.0),
|
||||||
assert(elevation == null || elevation >= 0.0);
|
assert(elevation == null || elevation >= 0.0);
|
||||||
|
|
||||||
@ -199,6 +200,8 @@ class InputChip extends StatelessWidget
|
|||||||
final BoxConstraints? avatarBoxConstraints;
|
final BoxConstraints? avatarBoxConstraints;
|
||||||
@override
|
@override
|
||||||
final BoxConstraints? deleteIconBoxConstraints;
|
final BoxConstraints? deleteIconBoxConstraints;
|
||||||
|
@override
|
||||||
|
final ChipAnimationStyle? chipAnimationStyle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -246,6 +249,7 @@ class InputChip extends StatelessWidget
|
|||||||
iconTheme: iconTheme,
|
iconTheme: iconTheme,
|
||||||
avatarBoxConstraints: avatarBoxConstraints,
|
avatarBoxConstraints: avatarBoxConstraints,
|
||||||
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
deleteIconBoxConstraints: deleteIconBoxConstraints,
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -493,4 +493,40 @@ void main() {
|
|||||||
labelTopLeft = tester.getTopLeft(find.byType(Container));
|
labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||||
expect(labelTopLeft.dx, avatarCenter.dx + (iconSize / 2) + labelPadding);
|
expect(labelTopLeft.dx, avatarCenter.dx + (iconSize / 2) + labelPadding);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('ActionChip.chipAnimationStyle is passed to RawChip', (WidgetTester tester) async {
|
||||||
|
final ChipAnimationStyle chipAnimationStyle = ChipAnimationStyle(
|
||||||
|
enableAnimation: AnimationStyle(duration: Durations.extralong4),
|
||||||
|
selectAnimation: AnimationStyle.noAnimation,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(wrapForChip(
|
||||||
|
child: Center(
|
||||||
|
child: ActionChip(
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
|
label: const Text('ActionChip'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Elevated ActionChip.chipAnimationStyle is passed to RawChip', (WidgetTester tester) async {
|
||||||
|
final ChipAnimationStyle chipAnimationStyle = ChipAnimationStyle(
|
||||||
|
enableAnimation: AnimationStyle(duration: Durations.extralong4),
|
||||||
|
selectAnimation: AnimationStyle.noAnimation,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(wrapForChip(
|
||||||
|
child: Center(
|
||||||
|
child: ActionChip.elevated(
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
|
label: const Text('ActionChip'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -5793,6 +5793,318 @@ void main() {
|
|||||||
|
|
||||||
expect(renderLayoutCount.layoutCount, 1);
|
expect(renderLayoutCount.layoutCount, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('ChipAnimationStyle.enableAnimation overrides chip enable animation duration', (WidgetTester tester) async {
|
||||||
|
const Color disabledColor = Color(0xffff0000);
|
||||||
|
const Color backgroundColor = Color(0xff00ff00);
|
||||||
|
bool enabled = true;
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
RawChip(
|
||||||
|
chipAnimationStyle: ChipAnimationStyle(
|
||||||
|
enableAnimation: AnimationStyle(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
reverseDuration: const Duration(milliseconds: 150),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
isEnabled: enabled,
|
||||||
|
disabledColor: disabledColor,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
label: const Text('RawChip'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
enabled = !enabled;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text('${enabled ? 'Disable' : 'Enable'} Chip'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
final RenderBox materialBox = tester.firstRenderObject<RenderBox>(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(RawChip),
|
||||||
|
matching: find.byType(CustomPaint),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test background color when the chip is enabled.
|
||||||
|
expect(materialBox, paints..rrect(color: backgroundColor));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Disable Chip'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 75));
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0x80ff0000)));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 75));
|
||||||
|
|
||||||
|
// Test background color when the chip is disabled.
|
||||||
|
expect(materialBox, paints..rrect(color: disabledColor));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Enable Chip'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 150));
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0x8000ff00)));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 150));
|
||||||
|
|
||||||
|
// Test background color when the chip is enabled.
|
||||||
|
expect(materialBox, paints..rrect(color: backgroundColor));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('ChipAnimationStyle.selectAnimation overrides chip selection animation duration', (WidgetTester tester) async {
|
||||||
|
const Color backgroundColor = Color(0xff00ff00);
|
||||||
|
const Color selectedColor = Color(0xff0000ff);
|
||||||
|
bool selected = false;
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
RawChip(
|
||||||
|
chipAnimationStyle: ChipAnimationStyle(
|
||||||
|
selectAnimation: AnimationStyle(
|
||||||
|
duration: const Duration(milliseconds: 600),
|
||||||
|
reverseDuration: const Duration(milliseconds: 300),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
selectedColor: selectedColor,
|
||||||
|
selected: selected,
|
||||||
|
onSelected: (bool value) {},
|
||||||
|
label: const Text('RawChip'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
selected = !selected;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text('${selected ? 'Unselect' : 'Select'} Chip'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
final RenderBox materialBox = tester.firstRenderObject<RenderBox>(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(RawChip),
|
||||||
|
matching: find.byType(CustomPaint),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test background color when the chip is unselected.
|
||||||
|
expect(materialBox, paints..rrect(color: backgroundColor));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Select Chip'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 300));
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0xc60000ff)));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 300));
|
||||||
|
|
||||||
|
// Test background color when the chip is selected.
|
||||||
|
expect(materialBox, paints..rrect(color: selectedColor));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Unselect Chip'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 150));
|
||||||
|
|
||||||
|
expect(materialBox, paints..rrect(color: const Color(0x3900ff00)));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 150));
|
||||||
|
|
||||||
|
// Test background color when the chip is unselected.
|
||||||
|
expect(materialBox, paints..rrect(color: backgroundColor));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('ChipAnimationStyle.avatarDrawerAnimation overrides chip avatar animation duration', (WidgetTester tester) async {
|
||||||
|
const Color checkmarkColor = Color(0xffff0000);
|
||||||
|
bool selected = false;
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
RawChip(
|
||||||
|
chipAnimationStyle: ChipAnimationStyle(
|
||||||
|
avatarDrawerAnimation: AnimationStyle(
|
||||||
|
duration: const Duration(milliseconds: 800),
|
||||||
|
reverseDuration: const Duration(milliseconds: 400),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
checkmarkColor: checkmarkColor,
|
||||||
|
selected: selected,
|
||||||
|
onSelected: (bool value) {},
|
||||||
|
label: const Text('RawChip'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
selected = !selected;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text('${selected ? 'Unselect' : 'Select'} Chip'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
final RenderBox materialBox = tester.firstRenderObject<RenderBox>(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(RawChip),
|
||||||
|
matching: find.byType(CustomPaint),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test the chechmark is not visible yet.
|
||||||
|
expect(materialBox, isNot(paints..path(color:checkmarkColor)));
|
||||||
|
expect(tester.getSize(find.byType(RawChip)).width, closeTo(132.6, 0.1));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Select Chip'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 400));
|
||||||
|
|
||||||
|
expect(materialBox, paints..path(color: checkmarkColor));
|
||||||
|
expect(tester.getSize(find.byType(RawChip)).width, closeTo(148.2, 0.1));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 400));
|
||||||
|
|
||||||
|
// Test the checkmark is fully visible.
|
||||||
|
expect(materialBox, paints..path(color: checkmarkColor));
|
||||||
|
expect(tester.getSize(find.byType(RawChip)).width, closeTo(152.6, 0.1));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Unselect Chip'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 200));
|
||||||
|
|
||||||
|
expect(materialBox, isNot(paints..path(color:checkmarkColor)));
|
||||||
|
expect(tester.getSize(find.byType(RawChip)).width, closeTo(148.2, 0.1));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 200));
|
||||||
|
|
||||||
|
// Test if checkmark is removed.
|
||||||
|
expect(materialBox, isNot(paints..path(color:checkmarkColor)));
|
||||||
|
expect(tester.getSize(find.byType(RawChip)).width, closeTo(132.6, 0.1));
|
||||||
|
}, skip: kIsWeb && !isSkiaWeb); // https://github.com/flutter/flutter/issues/99933
|
||||||
|
|
||||||
|
testWidgets('ChipAnimationStyle.deleteDrawerAnimation overrides chip delete icon animation duration', (WidgetTester tester) async {
|
||||||
|
bool showDeleteIcon = false;
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
RawChip(
|
||||||
|
chipAnimationStyle: ChipAnimationStyle(
|
||||||
|
deleteDrawerAnimation: AnimationStyle(
|
||||||
|
duration: const Duration(milliseconds: 500),
|
||||||
|
reverseDuration: const Duration(milliseconds: 250),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onDeleted: showDeleteIcon ? () {} : null,
|
||||||
|
label: const Text('RawChip'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
showDeleteIcon = !showDeleteIcon;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text('${showDeleteIcon ? 'Hide' : 'Show'} delete icon'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Test the delete icon is not visible yet.
|
||||||
|
expect(find.byIcon(Icons.cancel), findsNothing);
|
||||||
|
expect(tester.getSize(find.byType(RawChip)).width, closeTo(132.6, 0.1));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Show delete icon'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 250));
|
||||||
|
|
||||||
|
expect(find.byIcon(Icons.cancel), findsOneWidget);
|
||||||
|
expect(tester.getSize(find.byType(RawChip)).width, closeTo(148.2, 0.1));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 250));
|
||||||
|
|
||||||
|
// Test the delete icon is fully visible.
|
||||||
|
expect(find.byIcon(Icons.cancel), findsOneWidget);
|
||||||
|
expect(tester.getSize(find.byType(RawChip)).width, closeTo(152.6, 0.1));
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(ElevatedButton, 'Hide delete icon'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 125));
|
||||||
|
|
||||||
|
expect(find.byIcon(Icons.cancel), findsOneWidget);
|
||||||
|
expect(tester.getSize(find.byType(RawChip)).width, closeTo(148.2, 0.1));
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 125));
|
||||||
|
|
||||||
|
// Test if delete icon is removed.
|
||||||
|
expect(find.byIcon(Icons.cancel), findsNothing);
|
||||||
|
expect(tester.getSize(find.byType(RawChip)).width, closeTo(132.6, 0.1));
|
||||||
|
}, skip: kIsWeb && !isSkiaWeb); // https://github.com/flutter/flutter/issues/99933
|
||||||
|
|
||||||
|
testWidgets('Chip.chipAnimationStyle is passed to RawChip', (WidgetTester tester) async {
|
||||||
|
final ChipAnimationStyle chipAnimationStyle = ChipAnimationStyle(
|
||||||
|
enableAnimation: AnimationStyle.noAnimation,
|
||||||
|
selectAnimation: AnimationStyle(duration: Durations.long3),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(wrapForChip(
|
||||||
|
child: Center(
|
||||||
|
child: Chip(
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
|
label: const Text('Chip'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder {
|
class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder {
|
||||||
|
@ -775,4 +775,42 @@ void main() {
|
|||||||
labelTopLeft = tester.getTopLeft(find.byType(Container));
|
labelTopLeft = tester.getTopLeft(find.byType(Container));
|
||||||
expect(labelTopLeft.dx, avatarCenter.dx + (iconSize / 2) + labelPadding);
|
expect(labelTopLeft.dx, avatarCenter.dx + (iconSize / 2) + labelPadding);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('ChoiceChip.chipAnimationStyle is passed to RawChip', (WidgetTester tester) async {
|
||||||
|
final ChipAnimationStyle chipAnimationStyle = ChipAnimationStyle(
|
||||||
|
enableAnimation: AnimationStyle(duration: Durations.extralong4),
|
||||||
|
selectAnimation: AnimationStyle.noAnimation,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(wrapForChip(
|
||||||
|
child: Center(
|
||||||
|
child: ChoiceChip(
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
|
selected: true,
|
||||||
|
label: const Text('ChoiceChip'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Elevated ChoiceChip.chipAnimationStyle is passed to RawChip', (WidgetTester tester) async {
|
||||||
|
final ChipAnimationStyle chipAnimationStyle = ChipAnimationStyle(
|
||||||
|
enableAnimation: AnimationStyle(duration: Durations.extralong4),
|
||||||
|
selectAnimation: AnimationStyle.noAnimation,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(wrapForChip(
|
||||||
|
child: Center(
|
||||||
|
child: ChoiceChip.elevated(
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
|
selected: true,
|
||||||
|
label: const Text('ChoiceChip'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -1286,4 +1286,42 @@ void main() {
|
|||||||
labelTopRight = tester.getTopRight(find.byType(Container));
|
labelTopRight = tester.getTopRight(find.byType(Container));
|
||||||
expect(labelTopRight.dx, deleteIconCenter.dx - (iconSize / 2) - labelPadding);
|
expect(labelTopRight.dx, deleteIconCenter.dx - (iconSize / 2) - labelPadding);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('FilterChip.chipAnimationStyle is passed to RawChip', (WidgetTester tester) async {
|
||||||
|
final ChipAnimationStyle chipAnimationStyle = ChipAnimationStyle(
|
||||||
|
enableAnimation: AnimationStyle.noAnimation,
|
||||||
|
selectAnimation: AnimationStyle(duration: Durations.extralong4),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(wrapForChip(
|
||||||
|
child: Center(
|
||||||
|
child: FilterChip(
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
|
onSelected: (bool value) { },
|
||||||
|
label: const Text('FilterChip'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Elevated FilterChip.chipAnimationStyle is passed to RawChip', (WidgetTester tester) async {
|
||||||
|
final ChipAnimationStyle chipAnimationStyle = ChipAnimationStyle(
|
||||||
|
enableAnimation: AnimationStyle.noAnimation,
|
||||||
|
selectAnimation: AnimationStyle(duration: Durations.extralong4),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(wrapForChip(
|
||||||
|
child: Center(
|
||||||
|
child: FilterChip.elevated(
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
|
onSelected: (bool value) { },
|
||||||
|
label: const Text('FilterChip'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -599,4 +599,22 @@ void main() {
|
|||||||
labelTopRight = tester.getTopRight(find.byType(Container));
|
labelTopRight = tester.getTopRight(find.byType(Container));
|
||||||
expect(labelTopRight.dx, deleteIconCenter.dx - (iconSize / 2) - labelPadding);
|
expect(labelTopRight.dx, deleteIconCenter.dx - (iconSize / 2) - labelPadding);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('InputChip.chipAnimationStyle is passed to RawChip', (WidgetTester tester) async {
|
||||||
|
final ChipAnimationStyle chipAnimationStyle = ChipAnimationStyle(
|
||||||
|
enableAnimation: AnimationStyle(duration: Durations.short2),
|
||||||
|
selectAnimation: AnimationStyle.noAnimation,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(wrapForChip(
|
||||||
|
child: Center(
|
||||||
|
child: InputChip(
|
||||||
|
chipAnimationStyle: chipAnimationStyle,
|
||||||
|
label: const Text('InputChip'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(tester.widget<RawChip>(find.byType(RawChip)).chipAnimationStyle, chipAnimationStyle);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user