Skip to content

Commit e5f799a

Browse files
authored
refactor: Migrate Expansible animation properties to AnimationStyle for a less broad API surface (#177966)
## Changes * Add animationStyle to Exapnsible * Mark duration, curve and reverseCurve as deprecated * Add data driven fixes fixes: #177799 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing.
1 parent 2c817be commit e5f799a

6 files changed

Lines changed: 462 additions & 9 deletions

File tree

packages/flutter/lib/fix_data/fix_widgets/fix_widgets.yaml

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,134 @@
2020
# * Actions: fix_actions.yaml
2121
# * BuildContext: fix_build_context.yaml
2222
# * Element: fix_element.yaml
23+
# * Expansible: (in this file)
2324
# * ListWheelScrollView: fix_list_wheel_scroll_view.yaml
2425
version: 1
2526
transforms:
27+
# Changes made in https://github.com/flutter/flutter/pull/177966
28+
- title: "Migrate animation parameters to 'animationStyle'"
29+
date: 2025-04-01
30+
element:
31+
uris: [ 'widgets.dart', 'material.dart', 'cupertino.dart' ]
32+
constructor: ''
33+
inClass: 'Expansible'
34+
oneOf:
35+
- if: "duration != '' && curve != '' && reverseCurve != ''"
36+
changes:
37+
- kind: 'addParameter'
38+
index: 0
39+
name: 'animationStyle'
40+
style: optional_named
41+
argumentValue:
42+
expression: 'AnimationStyle(duration: {% duration %}, curve: {% curve %}, reverseCurve: {% reverseCurve %})'
43+
requiredIf: "duration != '' && curve != '' && reverseCurve != ''"
44+
- kind: 'removeParameter'
45+
name: 'duration'
46+
- kind: 'removeParameter'
47+
name: 'curve'
48+
- kind: 'removeParameter'
49+
name: 'reverseCurve'
50+
- if: "duration != '' && curve != '' && reverseCurve == ''"
51+
changes:
52+
- kind: 'addParameter'
53+
index: 0
54+
name: 'animationStyle'
55+
style: optional_named
56+
argumentValue:
57+
expression: 'AnimationStyle(duration: {% duration %}, curve: {% curve %})'
58+
requiredIf: "duration != '' && curve != ''"
59+
- kind: 'removeParameter'
60+
name: 'duration'
61+
- kind: 'removeParameter'
62+
name: 'curve'
63+
- kind: 'removeParameter'
64+
name: 'reverseCurve'
65+
- if: "duration != '' && curve == '' && reverseCurve != ''"
66+
changes:
67+
- kind: 'addParameter'
68+
index: 0
69+
name: 'animationStyle'
70+
style: optional_named
71+
argumentValue:
72+
expression: 'AnimationStyle(duration: {% duration %}, reverseCurve: {% reverseCurve %})'
73+
requiredIf: "duration != '' && reverseCurve != ''"
74+
- kind: 'removeParameter'
75+
name: 'duration'
76+
- kind: 'removeParameter'
77+
name: 'curve'
78+
- kind: 'removeParameter'
79+
name: 'reverseCurve'
80+
- if: "duration == '' && curve != '' && reverseCurve != ''"
81+
changes:
82+
- kind: 'addParameter'
83+
index: 0
84+
name: 'animationStyle'
85+
style: optional_named
86+
argumentValue:
87+
expression: 'AnimationStyle(curve: {% curve %}, reverseCurve: {% reverseCurve %})'
88+
requiredIf: "curve != '' && reverseCurve != ''"
89+
- kind: 'removeParameter'
90+
name: 'duration'
91+
- kind: 'removeParameter'
92+
name: 'curve'
93+
- kind: 'removeParameter'
94+
name: 'reverseCurve'
95+
- if: "duration != '' && curve == '' && reverseCurve == ''"
96+
changes:
97+
- kind: 'addParameter'
98+
index: 0
99+
name: 'animationStyle'
100+
style: optional_named
101+
argumentValue:
102+
expression: 'AnimationStyle(duration: {% duration %})'
103+
requiredIf: "duration != ''"
104+
- kind: 'removeParameter'
105+
name: 'duration'
106+
- kind: 'removeParameter'
107+
name: 'curve'
108+
- kind: 'removeParameter'
109+
name: 'reverseCurve'
110+
- if: "duration == '' && curve != '' && reverseCurve == ''"
111+
changes:
112+
- kind: 'addParameter'
113+
index: 0
114+
name: 'animationStyle'
115+
style: optional_named
116+
argumentValue:
117+
expression: 'AnimationStyle(curve: {% curve %})'
118+
requiredIf: "curve != ''"
119+
- kind: 'removeParameter'
120+
name: 'duration'
121+
- kind: 'removeParameter'
122+
name: 'curve'
123+
- kind: 'removeParameter'
124+
name: 'reverseCurve'
125+
- if: "duration == '' && curve == '' && reverseCurve != ''"
126+
changes:
127+
- kind: 'addParameter'
128+
index: 0
129+
name: 'animationStyle'
130+
style: optional_named
131+
argumentValue:
132+
expression: 'AnimationStyle(reverseCurve: {% reverseCurve %})'
133+
requiredIf: "reverseCurve != ''"
134+
- kind: 'removeParameter'
135+
name: 'duration'
136+
- kind: 'removeParameter'
137+
name: 'curve'
138+
- kind: 'removeParameter'
139+
name: 'reverseCurve'
140+
variables:
141+
duration:
142+
kind: 'fragment'
143+
value: 'arguments[duration]'
144+
curve:
145+
kind: 'fragment'
146+
value: 'arguments[curve]'
147+
reverseCurve:
148+
kind: 'fragment'
149+
value: 'arguments[reverseCurve]'
150+
26151
# Changes made in https://github.com/flutter/flutter/pull/139260
27152
- title: "Migrate to focusNode.enclosingScope!"
28153
date: 2023-11-29

packages/flutter/lib/src/animation/animation_style.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'tween.dart';
1313
/// Used to override the default parameters of an animation.
1414
///
1515
/// Currently, this class is used by the following widgets:
16+
/// - [Expansible]
1617
/// - [ExpansionTile]
1718
/// - [MaterialApp]
1819
/// - [PopupMenuButton]

packages/flutter/lib/src/widgets/expansible.dart

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,21 @@ class Expansible extends StatefulWidget {
222222
required this.bodyBuilder,
223223
required this.controller,
224224
this.expansibleBuilder = _defaultExpansibleBuilder,
225+
this.animationStyle,
226+
@Deprecated(
227+
'Use animationStyle instead. '
228+
'This feature was deprecated after v3.38.0-0.2.pre.',
229+
)
225230
this.duration = const Duration(milliseconds: 200),
231+
@Deprecated(
232+
'Use animationStyle instead. '
233+
'This feature was deprecated after v3.38.0-0.2.pre.',
234+
)
226235
this.curve = Curves.ease,
236+
@Deprecated(
237+
'Use animationStyle instead. '
238+
'This feature was deprecated after v3.38.0-0.2.pre.',
239+
)
227240
this.reverseCurve,
228241
this.maintainState = true,
229242
});
@@ -246,19 +259,54 @@ class Expansible extends StatefulWidget {
246259
/// its fully extended height.
247260
final ExpansibleComponentBuilder bodyBuilder;
248261

262+
/// Used to override the expansion animation curve and duration.
263+
///
264+
/// If [AnimationStyle.duration] is provided, it will be used instead of
265+
/// [duration]. If not provided, [duration] is used, which defaults to
266+
/// 200ms.
267+
///
268+
/// If [AnimationStyle.curve] is provided, it will be used to override
269+
/// [curve]. If it is null, then [curve] will be used. Otherwise, defaults
270+
/// to [Curves.ease].
271+
///
272+
/// If [AnimationStyle.reverseCurve] is provided, it will be used to
273+
/// override [reverseCurve]. If it is null, then [reverseCurve] will be
274+
/// used.
275+
///
276+
/// To disable the theme animation, use [AnimationStyle.noAnimation].
277+
final AnimationStyle? animationStyle;
278+
249279
/// The duration of the expansion animation.
250280
///
251281
/// Defaults to a duration of 200ms.
282+
///
283+
/// This property is deprecated, use [animationStyle] instead.
284+
@Deprecated(
285+
'Use animationStyle instead. '
286+
'This feature was deprecated after v3.38.0-0.2.pre.',
287+
)
252288
final Duration duration;
253289

254290
/// The curve of the expansion animation.
255291
///
256292
/// Defaults to [Curves.ease].
293+
///
294+
/// This property is deprecated, use [animationStyle] instead.
295+
@Deprecated(
296+
'Use animationStyle instead. '
297+
'This feature was deprecated after v3.38.0-0.2.pre.',
298+
)
257299
final Curve curve;
258300

259301
/// The reverse curve of the expansion animation.
260302
///
261303
/// If null, uses [curve] in both directions.
304+
///
305+
/// This property is deprecated, use [animationStyle] instead.
306+
@Deprecated(
307+
'Use animationStyle instead. '
308+
'This feature was deprecated after v3.38.0-0.2.pre.',
309+
)
262310
final Curve? reverseCurve;
263311

264312
/// Whether the state of the body is maintained when the widget expands or
@@ -293,10 +341,22 @@ class _ExpansibleState extends State<Expansible> with SingleTickerProviderStateM
293341
late AnimationController _animationController;
294342
late CurvedAnimation _heightFactor;
295343

344+
Duration get _duration {
345+
return widget.animationStyle?.duration ?? widget.duration;
346+
}
347+
348+
Curve get _curve {
349+
return widget.animationStyle?.curve ?? widget.curve;
350+
}
351+
352+
Curve? get _reverseCurve {
353+
return widget.animationStyle?.reverseCurve ?? widget.reverseCurve;
354+
}
355+
296356
@override
297357
void initState() {
298358
super.initState();
299-
_animationController = AnimationController(duration: widget.duration, vsync: this);
359+
_animationController = AnimationController(duration: _duration, vsync: this);
300360
final bool initiallyExpanded =
301361
PageStorage.maybeOf(context)?.readState(context) as bool? ?? widget.controller.isExpanded;
302362
if (initiallyExpanded) {
@@ -308,23 +368,27 @@ class _ExpansibleState extends State<Expansible> with SingleTickerProviderStateM
308368
final Tween<double> heightFactorTween = Tween<double>(begin: 0.0, end: 1.0);
309369
_heightFactor = CurvedAnimation(
310370
parent: _animationController.drive(heightFactorTween),
311-
curve: widget.curve,
312-
reverseCurve: widget.reverseCurve,
371+
curve: _curve,
372+
reverseCurve: _reverseCurve,
313373
);
314374
widget.controller.addListener(_toggleExpansion);
315375
}
316376

317377
@override
318378
void didUpdateWidget(covariant Expansible oldWidget) {
319379
super.didUpdateWidget(oldWidget);
320-
if (widget.curve != oldWidget.curve) {
321-
_heightFactor.curve = widget.curve;
380+
final Duration oldDuration = oldWidget.animationStyle?.duration ?? oldWidget.duration;
381+
final Curve oldCurve = oldWidget.animationStyle?.curve ?? oldWidget.curve;
382+
final Curve? oldReverseCurve = oldWidget.animationStyle?.reverseCurve ?? oldWidget.reverseCurve;
383+
384+
if (_curve != oldCurve) {
385+
_heightFactor.curve = _curve;
322386
}
323-
if (widget.reverseCurve != oldWidget.reverseCurve) {
324-
_heightFactor.reverseCurve = widget.reverseCurve;
387+
if (_reverseCurve != oldReverseCurve) {
388+
_heightFactor.reverseCurve = _reverseCurve;
325389
}
326-
if (widget.duration != oldWidget.duration) {
327-
_animationController.duration = widget.duration;
390+
if (_duration != oldDuration) {
391+
_animationController.duration = _duration;
328392
}
329393
if (widget.controller != oldWidget.controller) {
330394
oldWidget.controller.removeListener(_toggleExpansion);

0 commit comments

Comments
 (0)