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
652fb975
Unverified
Commit
652fb975
authored
Oct 26, 2019
by
Gary Qian
Committed by
GitHub
Oct 26, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
FadeInImage cacheWidth and cacheHeight support (#43286)
parent
50d8cc07
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
121 additions
and
16 deletions
+121
-16
image_provider.dart
packages/flutter/lib/src/painting/image_provider.dart
+12
-0
fade_in_image.dart
packages/flutter/lib/src/widgets/fade_in_image.dart
+30
-5
image.dart
packages/flutter/lib/src/widgets/image.dart
+4
-11
fade_in_image_test.dart
packages/flutter/test/widgets/fade_in_image_test.dart
+75
-0
No files found.
packages/flutter/lib/src/painting/image_provider.dart
View file @
652fb975
...
@@ -540,6 +540,18 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> {
...
@@ -540,6 +540,18 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> {
/// The height the image should decode to and cache.
/// The height the image should decode to and cache.
final
int
height
;
final
int
height
;
/// Composes the `provider` in a [ResizeImage] only when `cacheWidth` and
/// `cacheHeight` are not both null.
///
/// When `cacheWidth` and `cacheHeight` are both null, this will return the
/// `provider` directly.
static
ImageProvider
<
dynamic
>
resizeIfNeeded
(
int
cacheWidth
,
int
cacheHeight
,
ImageProvider
<
dynamic
>
provider
)
{
if
(
cacheWidth
!=
null
||
cacheHeight
!=
null
)
{
return
ResizeImage
(
provider
,
width:
cacheWidth
,
height:
cacheHeight
);
}
return
provider
;
}
@override
@override
ImageStreamCompleter
load
(
_SizeAwareCacheKey
key
,
DecoderCallback
decode
)
{
ImageStreamCompleter
load
(
_SizeAwareCacheKey
key
,
DecoderCallback
decode
)
{
final
DecoderCallback
decodeResize
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
final
DecoderCallback
decodeResize
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
...
...
packages/flutter/lib/src/widgets/fade_in_image.dart
View file @
652fb975
...
@@ -66,6 +66,9 @@ class FadeInImage extends StatelessWidget {
...
@@ -66,6 +66,9 @@ class FadeInImage extends StatelessWidget {
/// Creates a widget that displays a [placeholder] while an [image] is loading,
/// Creates a widget that displays a [placeholder] while an [image] is loading,
/// then fades-out the placeholder and fades-in the image.
/// then fades-out the placeholder and fades-in the image.
///
///
/// The [placeholder] and [image] may be composed in a [ResizeImage] to provide
/// a custom decode/cache size.
///
/// The [placeholder], [image], [fadeOutDuration], [fadeOutCurve],
/// The [placeholder], [image], [fadeOutDuration], [fadeOutCurve],
/// [fadeInDuration], [fadeInCurve], [alignment], [repeat], and
/// [fadeInDuration], [fadeInCurve], [alignment], [repeat], and
/// [matchTextDirection] arguments must not be null.
/// [matchTextDirection] arguments must not be null.
...
@@ -108,6 +111,13 @@ class FadeInImage extends StatelessWidget {
...
@@ -108,6 +111,13 @@ class FadeInImage extends StatelessWidget {
/// The `placeholderScale` and `imageScale` arguments are passed to their
/// The `placeholderScale` and `imageScale` arguments are passed to their
/// respective [ImageProvider]s (see also [ImageInfo.scale]).
/// respective [ImageProvider]s (see also [ImageInfo.scale]).
///
///
/// If [placeholderCacheWidth], [placeholderCacheHeight], [imageCacheWidth],
/// or [imageCacheHeight] are provided, it indicates to the
/// engine that the respective image should be decoded at the specified size.
/// The image will be rendered to the constraints of the layout or [width]
/// and [height] regardless of these parameters. These parameters are primarily
/// intended to reduce the memory usage of [ImageCache].
///
/// The [placeholder], [image], [placeholderScale], [imageScale],
/// The [placeholder], [image], [placeholderScale], [imageScale],
/// [fadeOutDuration], [fadeOutCurve], [fadeInDuration], [fadeInCurve],
/// [fadeOutDuration], [fadeOutCurve], [fadeInDuration], [fadeInCurve],
/// [alignment], [repeat], and [matchTextDirection] arguments must not be
/// [alignment], [repeat], and [matchTextDirection] arguments must not be
...
@@ -137,6 +147,10 @@ class FadeInImage extends StatelessWidget {
...
@@ -137,6 +147,10 @@ class FadeInImage extends StatelessWidget {
this
.
alignment
=
Alignment
.
center
,
this
.
alignment
=
Alignment
.
center
,
this
.
repeat
=
ImageRepeat
.
noRepeat
,
this
.
repeat
=
ImageRepeat
.
noRepeat
,
this
.
matchTextDirection
=
false
,
this
.
matchTextDirection
=
false
,
int
placeholderCacheWidth
,
int
placeholderCacheHeight
,
int
imageCacheWidth
,
int
imageCacheHeight
,
})
:
assert
(
placeholder
!=
null
),
})
:
assert
(
placeholder
!=
null
),
assert
(
image
!=
null
),
assert
(
image
!=
null
),
assert
(
placeholderScale
!=
null
),
assert
(
placeholderScale
!=
null
),
...
@@ -148,8 +162,8 @@ class FadeInImage extends StatelessWidget {
...
@@ -148,8 +162,8 @@ class FadeInImage extends StatelessWidget {
assert
(
alignment
!=
null
),
assert
(
alignment
!=
null
),
assert
(
repeat
!=
null
),
assert
(
repeat
!=
null
),
assert
(
matchTextDirection
!=
null
),
assert
(
matchTextDirection
!=
null
),
placeholder
=
MemoryImage
(
placeholder
,
scale:
placeholderScale
),
placeholder
=
ResizeImage
.
resizeIfNeeded
(
placeholderCacheWidth
,
placeholderCacheHeight
,
MemoryImage
(
placeholder
,
scale:
placeholderScale
)
),
image
=
NetworkImage
(
image
,
scale:
imageScale
),
image
=
ResizeImage
.
resizeIfNeeded
(
imageCacheWidth
,
imageCacheHeight
,
NetworkImage
(
image
,
scale:
imageScale
)
),
super
(
key:
key
);
super
(
key:
key
);
/// Creates a widget that uses a placeholder image stored in an asset bundle
/// Creates a widget that uses a placeholder image stored in an asset bundle
...
@@ -166,6 +180,13 @@ class FadeInImage extends StatelessWidget {
...
@@ -166,6 +180,13 @@ class FadeInImage extends StatelessWidget {
/// resolution will be attempted for the [placeholder] image. Otherwise, the
/// resolution will be attempted for the [placeholder] image. Otherwise, the
/// exact asset specified will be used.
/// exact asset specified will be used.
///
///
/// If [placeholderCacheWidth], [placeholderCacheHeight], [imageCacheWidth],
/// or [imageCacheHeight] are provided, it indicates to the
/// engine that the respective image should be decoded at the specified size.
/// The image will be rendered to the constraints of the layout or [width]
/// and [height] regardless of these parameters. These parameters are primarily
/// intended to reduce the memory usage of [ImageCache].
///
/// The [placeholder], [image], [imageScale], [fadeOutDuration],
/// The [placeholder], [image], [imageScale], [fadeOutDuration],
/// [fadeOutCurve], [fadeInDuration], [fadeInCurve], [alignment], [repeat],
/// [fadeOutCurve], [fadeInDuration], [fadeInCurve], [alignment], [repeat],
/// and [matchTextDirection] arguments must not be null.
/// and [matchTextDirection] arguments must not be null.
...
@@ -195,11 +216,15 @@ class FadeInImage extends StatelessWidget {
...
@@ -195,11 +216,15 @@ class FadeInImage extends StatelessWidget {
this
.
alignment
=
Alignment
.
center
,
this
.
alignment
=
Alignment
.
center
,
this
.
repeat
=
ImageRepeat
.
noRepeat
,
this
.
repeat
=
ImageRepeat
.
noRepeat
,
this
.
matchTextDirection
=
false
,
this
.
matchTextDirection
=
false
,
int
placeholderCacheWidth
,
int
placeholderCacheHeight
,
int
imageCacheWidth
,
int
imageCacheHeight
,
})
:
assert
(
placeholder
!=
null
),
})
:
assert
(
placeholder
!=
null
),
assert
(
image
!=
null
),
assert
(
image
!=
null
),
placeholder
=
placeholderScale
!=
null
placeholder
=
placeholderScale
!=
null
?
ExactAssetImage
(
placeholder
,
bundle:
bundle
,
scale:
placeholderScale
)
?
ResizeImage
.
resizeIfNeeded
(
placeholderCacheWidth
,
placeholderCacheHeight
,
ExactAssetImage
(
placeholder
,
bundle:
bundle
,
scale:
placeholderScale
)
)
:
AssetImage
(
placeholder
,
bundle:
bundle
),
:
ResizeImage
.
resizeIfNeeded
(
placeholderCacheWidth
,
placeholderCacheHeight
,
AssetImage
(
placeholder
,
bundle:
bundle
)
),
assert
(
imageScale
!=
null
),
assert
(
imageScale
!=
null
),
assert
(
fadeOutDuration
!=
null
),
assert
(
fadeOutDuration
!=
null
),
assert
(
fadeOutCurve
!=
null
),
assert
(
fadeOutCurve
!=
null
),
...
@@ -208,7 +233,7 @@ class FadeInImage extends StatelessWidget {
...
@@ -208,7 +233,7 @@ class FadeInImage extends StatelessWidget {
assert
(
alignment
!=
null
),
assert
(
alignment
!=
null
),
assert
(
repeat
!=
null
),
assert
(
repeat
!=
null
),
assert
(
matchTextDirection
!=
null
),
assert
(
matchTextDirection
!=
null
),
image
=
NetworkImage
(
image
,
scale:
imageScale
),
image
=
ResizeImage
.
resizeIfNeeded
(
imageCacheWidth
,
imageCacheHeight
,
NetworkImage
(
image
,
scale:
imageScale
)
),
super
(
key:
key
);
super
(
key:
key
);
/// Image displayed while the target [image] is loading.
/// Image displayed while the target [image] is loading.
...
...
packages/flutter/lib/src/widgets/image.dart
View file @
652fb975
...
@@ -55,13 +55,6 @@ ImageConfiguration createLocalImageConfiguration(BuildContext context, { Size si
...
@@ -55,13 +55,6 @@ ImageConfiguration createLocalImageConfiguration(BuildContext context, { Size si
);
);
}
}
ImageProvider
<
dynamic
>
_resizeIfNeeded
(
int
cacheWidth
,
int
cacheHeight
,
ImageProvider
<
dynamic
>
provider
)
{
if
(
cacheWidth
!=
null
||
cacheHeight
!=
null
)
{
return
ResizeImage
(
provider
,
width:
cacheWidth
,
height:
cacheHeight
);
}
return
provider
;
}
/// Prefetches an image into the image cache.
/// Prefetches an image into the image cache.
///
///
/// Returns a [Future] that will complete when the first image yielded by the
/// Returns a [Future] that will complete when the first image yielded by the
...
@@ -358,7 +351,7 @@ class Image extends StatefulWidget {
...
@@ -358,7 +351,7 @@ class Image extends StatefulWidget {
Map
<
String
,
String
>
headers
,
Map
<
String
,
String
>
headers
,
int
cacheWidth
,
int
cacheWidth
,
int
cacheHeight
,
int
cacheHeight
,
})
:
image
=
_
resizeIfNeeded
(
cacheWidth
,
cacheHeight
,
NetworkImage
(
src
,
scale:
scale
,
headers:
headers
)),
})
:
image
=
ResizeImage
.
resizeIfNeeded
(
cacheWidth
,
cacheHeight
,
NetworkImage
(
src
,
scale:
scale
,
headers:
headers
)),
assert
(
alignment
!=
null
),
assert
(
alignment
!=
null
),
assert
(
repeat
!=
null
),
assert
(
repeat
!=
null
),
assert
(
matchTextDirection
!=
null
),
assert
(
matchTextDirection
!=
null
),
...
@@ -410,7 +403,7 @@ class Image extends StatefulWidget {
...
@@ -410,7 +403,7 @@ class Image extends StatefulWidget {
this
.
filterQuality
=
FilterQuality
.
low
,
this
.
filterQuality
=
FilterQuality
.
low
,
int
cacheWidth
,
int
cacheWidth
,
int
cacheHeight
,
int
cacheHeight
,
})
:
image
=
_
resizeIfNeeded
(
cacheWidth
,
cacheHeight
,
FileImage
(
file
,
scale:
scale
)),
})
:
image
=
ResizeImage
.
resizeIfNeeded
(
cacheWidth
,
cacheHeight
,
FileImage
(
file
,
scale:
scale
)),
loadingBuilder
=
null
,
loadingBuilder
=
null
,
assert
(
alignment
!=
null
),
assert
(
alignment
!=
null
),
assert
(
repeat
!=
null
),
assert
(
repeat
!=
null
),
...
@@ -573,7 +566,7 @@ class Image extends StatefulWidget {
...
@@ -573,7 +566,7 @@ class Image extends StatefulWidget {
this
.
filterQuality
=
FilterQuality
.
low
,
this
.
filterQuality
=
FilterQuality
.
low
,
int
cacheWidth
,
int
cacheWidth
,
int
cacheHeight
,
int
cacheHeight
,
})
:
image
=
_
resizeIfNeeded
(
cacheWidth
,
cacheHeight
,
scale
!=
null
})
:
image
=
ResizeImage
.
resizeIfNeeded
(
cacheWidth
,
cacheHeight
,
scale
!=
null
?
ExactAssetImage
(
name
,
bundle:
bundle
,
scale:
scale
,
package:
package
)
?
ExactAssetImage
(
name
,
bundle:
bundle
,
scale:
scale
,
package:
package
)
:
AssetImage
(
name
,
bundle:
bundle
,
package:
package
)
:
AssetImage
(
name
,
bundle:
bundle
,
package:
package
)
),
),
...
@@ -630,7 +623,7 @@ class Image extends StatefulWidget {
...
@@ -630,7 +623,7 @@ class Image extends StatefulWidget {
this
.
filterQuality
=
FilterQuality
.
low
,
this
.
filterQuality
=
FilterQuality
.
low
,
int
cacheWidth
,
int
cacheWidth
,
int
cacheHeight
,
int
cacheHeight
,
})
:
image
=
_
resizeIfNeeded
(
cacheWidth
,
cacheHeight
,
MemoryImage
(
bytes
,
scale:
scale
)),
})
:
image
=
ResizeImage
.
resizeIfNeeded
(
cacheWidth
,
cacheHeight
,
MemoryImage
(
bytes
,
scale:
scale
)),
loadingBuilder
=
null
,
loadingBuilder
=
null
,
assert
(
alignment
!=
null
),
assert
(
alignment
!=
null
),
assert
(
repeat
!=
null
),
assert
(
repeat
!=
null
),
...
...
packages/flutter/test/widgets/fade_in_image_test.dart
View file @
652fb975
...
@@ -3,10 +3,13 @@
...
@@ -3,10 +3,13 @@
// found in the LICENSE file.
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:async'
;
import
'dart:typed_data'
;
import
'dart:ui'
as
ui
;
import
'dart:ui'
as
ui
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/painting.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'../painting/image_data.dart'
;
import
'../painting/image_test_utils.dart'
;
import
'../painting/image_test_utils.dart'
;
const
Duration
animationDuration
=
Duration
(
milliseconds:
50
);
const
Duration
animationDuration
=
Duration
(
milliseconds:
50
);
...
@@ -51,6 +54,26 @@ class FadeInImageElements {
...
@@ -51,6 +54,26 @@ class FadeInImageElements {
double
get
opacity
=>
fadeTransition
==
null
?
1
:
fadeTransition
.
opacity
.
value
;
double
get
opacity
=>
fadeTransition
==
null
?
1
:
fadeTransition
.
opacity
.
value
;
}
}
class
LoadTestImageProvider
extends
ImageProvider
<
dynamic
>
{
LoadTestImageProvider
(
this
.
provider
);
final
ImageProvider
provider
;
ImageStreamCompleter
testLoad
(
dynamic
key
,
DecoderCallback
decode
)
{
return
provider
.
load
(
key
,
decode
);
}
@override
Future
<
dynamic
>
obtainKey
(
ImageConfiguration
configuration
)
{
return
null
;
}
@override
ImageStreamCompleter
load
(
dynamic
key
,
DecoderCallback
decode
)
{
return
null
;
}
}
FadeInImageParts
findFadeInImage
(
WidgetTester
tester
)
{
FadeInImageParts
findFadeInImage
(
WidgetTester
tester
)
{
final
List
<
FadeInImageElements
>
elements
=
<
FadeInImageElements
>[];
final
List
<
FadeInImageElements
>
elements
=
<
FadeInImageElements
>[];
final
Iterable
<
Element
>
rawImageElements
=
tester
.
elementList
(
find
.
byType
(
RawImage
));
final
Iterable
<
Element
>
rawImageElements
=
tester
.
elementList
(
find
.
byType
(
RawImage
));
...
@@ -262,6 +285,58 @@ Future<void> main() async {
...
@@ -262,6 +285,58 @@ Future<void> main() async {
expect
(
findFadeInImage
(
tester
).
target
.
opacity
,
moreOrLessEquals
(
1
));
expect
(
findFadeInImage
(
tester
).
target
.
opacity
,
moreOrLessEquals
(
1
));
});
});
group
(
ImageProvider
,
()
{
testWidgets
(
'memory placeholder cacheWidth and cacheHeight is passed through'
,
(
WidgetTester
tester
)
async
{
final
Uint8List
testBytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
FadeInImage
image
=
FadeInImage
.
memoryNetwork
(
placeholder:
testBytes
,
image:
'test.com'
,
placeholderCacheWidth:
20
,
placeholderCacheHeight:
30
,
imageCacheWidth:
40
,
imageCacheHeight:
50
,
);
bool
called
=
false
;
final
DecoderCallback
decode
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
expect
(
cacheWidth
,
20
);
expect
(
cacheHeight
,
30
);
called
=
true
;
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
);
};
final
ImageProvider
resizeImage
=
image
.
placeholder
;
expect
(
image
.
placeholder
,
isA
<
ResizeImage
>());
expect
(
called
,
false
);
final
LoadTestImageProvider
testProvider
=
LoadTestImageProvider
(
image
.
placeholder
);
testProvider
.
testLoad
(
await
resizeImage
.
obtainKey
(
ImageConfiguration
.
empty
),
decode
);
expect
(
called
,
true
);
});
testWidgets
(
'do not resize when null cache dimensions'
,
(
WidgetTester
tester
)
async
{
final
Uint8List
testBytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
FadeInImage
image
=
FadeInImage
.
memoryNetwork
(
placeholder:
testBytes
,
image:
'test.com'
,
);
bool
called
=
false
;
final
DecoderCallback
decode
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
expect
(
cacheWidth
,
null
);
expect
(
cacheHeight
,
null
);
called
=
true
;
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
);
};
// image.placeholder should be an instance of MemoryImage instead of ResizeImage
final
ImageProvider
memoryImage
=
image
.
placeholder
;
expect
(
image
.
placeholder
,
isA
<
MemoryImage
>());
expect
(
called
,
false
);
final
LoadTestImageProvider
testProvider
=
LoadTestImageProvider
(
image
.
placeholder
);
testProvider
.
testLoad
(
await
memoryImage
.
obtainKey
(
ImageConfiguration
.
empty
),
decode
);
expect
(
called
,
true
);
});
});
group
(
'semantics'
,
()
{
group
(
'semantics'
,
()
{
testWidgets
(
'only one Semantics node appears within FadeInImage'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'only one Semantics node appears within FadeInImage'
,
(
WidgetTester
tester
)
async
{
final
TestImageProvider
placeholderProvider
=
TestImageProvider
(
placeholderImage
);
final
TestImageProvider
placeholderProvider
=
TestImageProvider
(
placeholderImage
);
...
...
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