Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
ea19a77b
Unverified
Commit
ea19a77b
authored
Apr 12, 2022
by
Jonah Williams
Committed by
GitHub
Apr 12, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[framework] elide ImageFilter layers when animation is stopped (#101731)
parent
88246030
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
144 additions
and
2 deletions
+144
-2
transitions.dart
packages/flutter/lib/src/widgets/transitions.dart
+38
-2
transitions_test.dart
packages/flutter/test/widgets/transitions_test.dart
+106
-0
No files found.
packages/flutter/lib/src/widgets/transitions.dart
View file @
ea19a77b
...
...
@@ -274,6 +274,9 @@ class ScaleTransition extends AnimatedWidget {
/// The filter quality with which to apply the transform as a bitmap operation.
///
/// When the animation is stopped (either in [AnimationStatus.dismissed] or
/// [AnimationStatus.completed]), the filter quality argument will be ignored.
///
/// {@macro flutter.widgets.Transform.optional.FilterQuality}
final
FilterQuality
?
filterQuality
;
...
...
@@ -284,10 +287,25 @@ class ScaleTransition extends AnimatedWidget {
@override
Widget
build
(
BuildContext
context
)
{
// The ImageFilter layer created by setting filterQuality will introduce
// a saveLayer call. This is usually worthwhile when animating the layer,
// but leaving it in the layer tree before the animation has started or after
// it has finished significantly hurts performance.
final
bool
useFilterQuality
;
switch
(
scale
.
status
)
{
case
AnimationStatus
.
dismissed
:
case
AnimationStatus
.
completed
:
useFilterQuality
=
false
;
break
;
case
AnimationStatus
.
forward
:
case
AnimationStatus
.
reverse
:
useFilterQuality
=
true
;
break
;
}
return
Transform
.
scale
(
scale:
scale
.
value
,
alignment:
alignment
,
filterQuality:
filterQuality
,
filterQuality:
useFilterQuality
?
filterQuality
:
null
,
child:
child
,
);
}
...
...
@@ -340,6 +358,9 @@ class RotationTransition extends AnimatedWidget {
/// The filter quality with which to apply the transform as a bitmap operation.
///
/// When the animation is stopped (either in [AnimationStatus.dismissed] or
/// [AnimationStatus.completed]), the filter quality argument will be ignored.
///
/// {@macro flutter.widgets.Transform.optional.FilterQuality}
final
FilterQuality
?
filterQuality
;
...
...
@@ -350,10 +371,25 @@ class RotationTransition extends AnimatedWidget {
@override
Widget
build
(
BuildContext
context
)
{
// The ImageFilter layer created by setting filterQuality will introduce
// a saveLayer call. This is usually worthwhile when animating the layer,
// but leaving it in the layer tree before the animation has started or after
// it has finished significantly hurts performance.
final
bool
useFilterQuality
;
switch
(
turns
.
status
)
{
case
AnimationStatus
.
dismissed
:
case
AnimationStatus
.
completed
:
useFilterQuality
=
false
;
break
;
case
AnimationStatus
.
forward
:
case
AnimationStatus
.
reverse
:
useFilterQuality
=
true
;
break
;
}
return
Transform
.
rotate
(
angle:
turns
.
value
*
math
.
pi
*
2.0
,
alignment:
alignment
,
filterQuality:
filterQuality
,
filterQuality:
useFilterQuality
?
filterQuality
:
null
,
child:
child
,
);
}
...
...
packages/flutter/test/widgets/transitions_test.dart
View file @
ea19a77b
...
...
@@ -446,4 +446,110 @@ void main() {
expect
(
_getOpacity
(
tester
,
'Fade In'
),
1.0
);
});
});
group
(
'ScaleTransition'
,
()
{
testWidgets
(
'uses ImageFilter when provided with FilterQuality argument'
,
(
WidgetTester
tester
)
async
{
final
AnimationController
controller
=
AnimationController
(
vsync:
const
TestVSync
());
final
Animation
<
double
>
animation
=
Tween
<
double
>(
begin:
0.0
,
end:
1.0
).
animate
(
controller
);
final
Widget
widget
=
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
ScaleTransition
(
scale:
animation
,
filterQuality:
FilterQuality
.
none
,
child:
const
Text
(
'Scale Transition'
),
),
);
await
tester
.
pumpWidget
(
widget
);
// Validate that expensive layer is not left in tree before animation has started.
expect
(
tester
.
layers
,
isNot
(
contains
(
isA
<
ImageFilterLayer
>())));
controller
.
value
=
0.25
;
await
tester
.
pump
();
expect
(
tester
.
layers
,
contains
(
isA
<
ImageFilterLayer
>().
having
(
(
ImageFilterLayer
layer
)
=>
layer
.
imageFilter
.
toString
(),
'image filter'
,
startsWith
(
'ImageFilter.matrix('
),
)));
controller
.
value
=
0.5
;
await
tester
.
pump
();
expect
(
tester
.
layers
,
contains
(
isA
<
ImageFilterLayer
>().
having
(
(
ImageFilterLayer
layer
)
=>
layer
.
imageFilter
.
toString
(),
'image filter'
,
startsWith
(
'ImageFilter.matrix('
),
)));
controller
.
value
=
0.75
;
await
tester
.
pump
();
expect
(
tester
.
layers
,
contains
(
isA
<
ImageFilterLayer
>().
having
(
(
ImageFilterLayer
layer
)
=>
layer
.
imageFilter
.
toString
(),
'image filter'
,
startsWith
(
'ImageFilter.matrix('
),
)));
controller
.
value
=
1
;
await
tester
.
pump
();
// Validate that expensive layer is not left in tree after animation has finished.
expect
(
tester
.
layers
,
isNot
(
contains
(
isA
<
ImageFilterLayer
>())));
});
});
group
(
'RotationTransition'
,
()
{
testWidgets
(
'uses ImageFilter when provided with FilterQuality argument'
,
(
WidgetTester
tester
)
async
{
final
AnimationController
controller
=
AnimationController
(
vsync:
const
TestVSync
());
final
Animation
<
double
>
animation
=
Tween
<
double
>(
begin:
0.0
,
end:
1.0
).
animate
(
controller
);
final
Widget
widget
=
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
RotationTransition
(
turns:
animation
,
filterQuality:
FilterQuality
.
none
,
child:
const
Text
(
'Scale Transition'
),
),
);
await
tester
.
pumpWidget
(
widget
);
// Validate that expensive layer is not left in tree before animation has started.
expect
(
tester
.
layers
,
isNot
(
contains
(
isA
<
ImageFilterLayer
>())));
controller
.
value
=
0.25
;
await
tester
.
pump
();
expect
(
tester
.
layers
,
contains
(
isA
<
ImageFilterLayer
>().
having
(
(
ImageFilterLayer
layer
)
=>
layer
.
imageFilter
.
toString
(),
'image filter'
,
startsWith
(
'ImageFilter.matrix('
),
)));
controller
.
value
=
0.5
;
await
tester
.
pump
();
expect
(
tester
.
layers
,
contains
(
isA
<
ImageFilterLayer
>().
having
(
(
ImageFilterLayer
layer
)
=>
layer
.
imageFilter
.
toString
(),
'image filter'
,
startsWith
(
'ImageFilter.matrix('
),
)));
controller
.
value
=
0.75
;
await
tester
.
pump
();
expect
(
tester
.
layers
,
contains
(
isA
<
ImageFilterLayer
>().
having
(
(
ImageFilterLayer
layer
)
=>
layer
.
imageFilter
.
toString
(),
'image filter'
,
startsWith
(
'ImageFilter.matrix('
),
)));
controller
.
value
=
1
;
await
tester
.
pump
();
// Validate that expensive layer is not left in tree after animation has finished.
expect
(
tester
.
layers
,
isNot
(
contains
(
isA
<
ImageFilterLayer
>())));
});
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment