Add error callbacks to other image resolving code (#53329)
This commit is contained in:
parent
0d111bc91a
commit
ed67c47982
@ -17,6 +17,9 @@ import 'theme_data.dart';
|
|||||||
/// such an image, the user's initials. A given user's initials should
|
/// such an image, the user's initials. A given user's initials should
|
||||||
/// always be paired with the same background color, for consistency.
|
/// always be paired with the same background color, for consistency.
|
||||||
///
|
///
|
||||||
|
/// The [onBackgroundImageError] parameter must be null if the [backgroundImage]
|
||||||
|
/// is null.
|
||||||
|
///
|
||||||
/// {@tool snippet}
|
/// {@tool snippet}
|
||||||
///
|
///
|
||||||
/// If the avatar is to have an image, the image should be specified in the
|
/// If the avatar is to have an image, the image should be specified in the
|
||||||
@ -57,11 +60,13 @@ class CircleAvatar extends StatelessWidget {
|
|||||||
this.child,
|
this.child,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.backgroundImage,
|
this.backgroundImage,
|
||||||
|
this.onBackgroundImageError,
|
||||||
this.foregroundColor,
|
this.foregroundColor,
|
||||||
this.radius,
|
this.radius,
|
||||||
this.minRadius,
|
this.minRadius,
|
||||||
this.maxRadius,
|
this.maxRadius,
|
||||||
}) : assert(radius == null || (minRadius == null && maxRadius == null)),
|
}) : assert(radius == null || (minRadius == null && maxRadius == null)),
|
||||||
|
assert(backgroundImage != null || onBackgroundImageError == null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// The widget below this widget in the tree.
|
/// The widget below this widget in the tree.
|
||||||
@ -93,6 +98,10 @@ class CircleAvatar extends StatelessWidget {
|
|||||||
/// If the [CircleAvatar] is to have the user's initials, use [child] instead.
|
/// If the [CircleAvatar] is to have the user's initials, use [child] instead.
|
||||||
final ImageProvider backgroundImage;
|
final ImageProvider backgroundImage;
|
||||||
|
|
||||||
|
/// An optional error callback for errors emitted when loading
|
||||||
|
/// [backgroundImage].
|
||||||
|
final ImageErrorListener onBackgroundImageError;
|
||||||
|
|
||||||
/// The size of the avatar, expressed as the radius (half the diameter).
|
/// The size of the avatar, expressed as the radius (half the diameter).
|
||||||
///
|
///
|
||||||
/// If [radius] is specified, then neither [minRadius] nor [maxRadius] may be
|
/// If [radius] is specified, then neither [minRadius] nor [maxRadius] may be
|
||||||
@ -200,7 +209,11 @@ class CircleAvatar extends StatelessWidget {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: effectiveBackgroundColor,
|
color: effectiveBackgroundColor,
|
||||||
image: backgroundImage != null
|
image: backgroundImage != null
|
||||||
? DecorationImage(image: backgroundImage, fit: BoxFit.cover)
|
? DecorationImage(
|
||||||
|
image: backgroundImage,
|
||||||
|
onError: onBackgroundImageError,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
)
|
||||||
: null,
|
: null,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
|
@ -145,7 +145,8 @@ class Ink extends StatefulWidget {
|
|||||||
///
|
///
|
||||||
/// The `image` argument must not be null. If there is no
|
/// The `image` argument must not be null. If there is no
|
||||||
/// intention to render anything on this image, consider using a
|
/// intention to render anything on this image, consider using a
|
||||||
/// [Container] with a [BoxDecoration.image] instead.
|
/// [Container] with a [BoxDecoration.image] instead. The `onImageError`
|
||||||
|
/// argument may be provided to listen for errors when resolving the image.
|
||||||
///
|
///
|
||||||
/// The `alignment`, `repeat`, and `matchTextDirection` arguments must not
|
/// The `alignment`, `repeat`, and `matchTextDirection` arguments must not
|
||||||
/// be null either, but they have default values.
|
/// be null either, but they have default values.
|
||||||
@ -155,6 +156,7 @@ class Ink extends StatefulWidget {
|
|||||||
Key key,
|
Key key,
|
||||||
this.padding,
|
this.padding,
|
||||||
@required ImageProvider image,
|
@required ImageProvider image,
|
||||||
|
ImageErrorListener onImageError,
|
||||||
ColorFilter colorFilter,
|
ColorFilter colorFilter,
|
||||||
BoxFit fit,
|
BoxFit fit,
|
||||||
AlignmentGeometry alignment = Alignment.center,
|
AlignmentGeometry alignment = Alignment.center,
|
||||||
@ -172,6 +174,7 @@ class Ink extends StatefulWidget {
|
|||||||
decoration = BoxDecoration(
|
decoration = BoxDecoration(
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
image: image,
|
image: image,
|
||||||
|
onError: onImageError,
|
||||||
colorFilter: colorFilter,
|
colorFilter: colorFilter,
|
||||||
fit: fit,
|
fit: fit,
|
||||||
alignment: alignment,
|
alignment: alignment,
|
||||||
|
@ -71,7 +71,9 @@ class Switch extends StatefulWidget {
|
|||||||
this.inactiveThumbColor,
|
this.inactiveThumbColor,
|
||||||
this.inactiveTrackColor,
|
this.inactiveTrackColor,
|
||||||
this.activeThumbImage,
|
this.activeThumbImage,
|
||||||
|
this.onActiveThumbImageError,
|
||||||
this.inactiveThumbImage,
|
this.inactiveThumbImage,
|
||||||
|
this.onInactiveThumbImageError,
|
||||||
this.materialTapTargetSize,
|
this.materialTapTargetSize,
|
||||||
this.dragStartBehavior = DragStartBehavior.start,
|
this.dragStartBehavior = DragStartBehavior.start,
|
||||||
this.focusColor,
|
this.focusColor,
|
||||||
@ -80,6 +82,8 @@ class Switch extends StatefulWidget {
|
|||||||
this.autofocus = false,
|
this.autofocus = false,
|
||||||
}) : _switchType = _SwitchType.material,
|
}) : _switchType = _SwitchType.material,
|
||||||
assert(dragStartBehavior != null),
|
assert(dragStartBehavior != null),
|
||||||
|
assert(activeThumbImage != null || onActiveThumbImageError == null),
|
||||||
|
assert(inactiveThumbImage != null || onInactiveThumbImageError == null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// Creates a [CupertinoSwitch] if the target platform is iOS, creates a
|
/// Creates a [CupertinoSwitch] if the target platform is iOS, creates a
|
||||||
@ -87,7 +91,8 @@ class Switch extends StatefulWidget {
|
|||||||
///
|
///
|
||||||
/// If a [CupertinoSwitch] is created, the following parameters are
|
/// If a [CupertinoSwitch] is created, the following parameters are
|
||||||
/// ignored: [activeTrackColor], [inactiveThumbColor], [inactiveTrackColor],
|
/// ignored: [activeTrackColor], [inactiveThumbColor], [inactiveTrackColor],
|
||||||
/// [activeThumbImage], [inactiveThumbImage], [materialTapTargetSize].
|
/// [activeThumbImage], [onActiveThumbImageError], [inactiveThumbImage],
|
||||||
|
/// [onInactiveImageThumbError], [materialTapTargetSize].
|
||||||
///
|
///
|
||||||
/// The target platform is based on the current [Theme]: [ThemeData.platform].
|
/// The target platform is based on the current [Theme]: [ThemeData.platform].
|
||||||
const Switch.adaptive({
|
const Switch.adaptive({
|
||||||
@ -99,7 +104,9 @@ class Switch extends StatefulWidget {
|
|||||||
this.inactiveThumbColor,
|
this.inactiveThumbColor,
|
||||||
this.inactiveTrackColor,
|
this.inactiveTrackColor,
|
||||||
this.activeThumbImage,
|
this.activeThumbImage,
|
||||||
|
this.onActiveThumbImageError,
|
||||||
this.inactiveThumbImage,
|
this.inactiveThumbImage,
|
||||||
|
this.onInactiveThumbImageError,
|
||||||
this.materialTapTargetSize,
|
this.materialTapTargetSize,
|
||||||
this.dragStartBehavior = DragStartBehavior.start,
|
this.dragStartBehavior = DragStartBehavior.start,
|
||||||
this.focusColor,
|
this.focusColor,
|
||||||
@ -107,6 +114,8 @@ class Switch extends StatefulWidget {
|
|||||||
this.focusNode,
|
this.focusNode,
|
||||||
this.autofocus = false,
|
this.autofocus = false,
|
||||||
}) : assert(autofocus != null),
|
}) : assert(autofocus != null),
|
||||||
|
assert(activeThumbImage != null || onActiveThumbImageError == null),
|
||||||
|
assert(inactiveThumbImage != null || onInactiveThumbImageError == null),
|
||||||
_switchType = _SwitchType.adaptive,
|
_switchType = _SwitchType.adaptive,
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@ -170,11 +179,19 @@ class Switch extends StatefulWidget {
|
|||||||
/// Ignored if this switch is created with [Switch.adaptive].
|
/// Ignored if this switch is created with [Switch.adaptive].
|
||||||
final ImageProvider activeThumbImage;
|
final ImageProvider activeThumbImage;
|
||||||
|
|
||||||
|
/// An optional error callback for errors emitted when loading
|
||||||
|
/// [activeThumbImage].
|
||||||
|
final ImageErrorListener onActiveThumbImageError;
|
||||||
|
|
||||||
/// An image to use on the thumb of this switch when the switch is off.
|
/// An image to use on the thumb of this switch when the switch is off.
|
||||||
///
|
///
|
||||||
/// Ignored if this switch is created with [Switch.adaptive].
|
/// Ignored if this switch is created with [Switch.adaptive].
|
||||||
final ImageProvider inactiveThumbImage;
|
final ImageProvider inactiveThumbImage;
|
||||||
|
|
||||||
|
/// An optional error callback for errors emitted when loading
|
||||||
|
/// [inactiveThumbImage].
|
||||||
|
final ImageErrorListener onInactiveThumbImageError;
|
||||||
|
|
||||||
/// Configures the minimum size of the tap target.
|
/// Configures the minimum size of the tap target.
|
||||||
///
|
///
|
||||||
/// Defaults to [ThemeData.materialTapTargetSize].
|
/// Defaults to [ThemeData.materialTapTargetSize].
|
||||||
@ -311,7 +328,9 @@ class _SwitchState extends State<Switch> with TickerProviderStateMixin {
|
|||||||
hoverColor: hoverColor,
|
hoverColor: hoverColor,
|
||||||
focusColor: focusColor,
|
focusColor: focusColor,
|
||||||
activeThumbImage: widget.activeThumbImage,
|
activeThumbImage: widget.activeThumbImage,
|
||||||
|
onActiveThumbImageError: widget.onActiveThumbImageError,
|
||||||
inactiveThumbImage: widget.inactiveThumbImage,
|
inactiveThumbImage: widget.inactiveThumbImage,
|
||||||
|
onInactiveThumbImageError: widget.onInactiveThumbImageError,
|
||||||
activeTrackColor: activeTrackColor,
|
activeTrackColor: activeTrackColor,
|
||||||
inactiveTrackColor: inactiveTrackColor,
|
inactiveTrackColor: inactiveTrackColor,
|
||||||
configuration: createLocalImageConfiguration(context),
|
configuration: createLocalImageConfiguration(context),
|
||||||
@ -381,7 +400,9 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
|
|||||||
this.hoverColor,
|
this.hoverColor,
|
||||||
this.focusColor,
|
this.focusColor,
|
||||||
this.activeThumbImage,
|
this.activeThumbImage,
|
||||||
|
this.onActiveThumbImageError,
|
||||||
this.inactiveThumbImage,
|
this.inactiveThumbImage,
|
||||||
|
this.onInactiveThumbImageError,
|
||||||
this.activeTrackColor,
|
this.activeTrackColor,
|
||||||
this.inactiveTrackColor,
|
this.inactiveTrackColor,
|
||||||
this.configuration,
|
this.configuration,
|
||||||
@ -399,7 +420,9 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
|
|||||||
final Color hoverColor;
|
final Color hoverColor;
|
||||||
final Color focusColor;
|
final Color focusColor;
|
||||||
final ImageProvider activeThumbImage;
|
final ImageProvider activeThumbImage;
|
||||||
|
final ImageErrorListener onActiveThumbImageError;
|
||||||
final ImageProvider inactiveThumbImage;
|
final ImageProvider inactiveThumbImage;
|
||||||
|
final ImageErrorListener onInactiveThumbImageError;
|
||||||
final Color activeTrackColor;
|
final Color activeTrackColor;
|
||||||
final Color inactiveTrackColor;
|
final Color inactiveTrackColor;
|
||||||
final ImageConfiguration configuration;
|
final ImageConfiguration configuration;
|
||||||
@ -420,7 +443,9 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
|
|||||||
hoverColor: hoverColor,
|
hoverColor: hoverColor,
|
||||||
focusColor: focusColor,
|
focusColor: focusColor,
|
||||||
activeThumbImage: activeThumbImage,
|
activeThumbImage: activeThumbImage,
|
||||||
|
onActiveThumbImageError: onActiveThumbImageError,
|
||||||
inactiveThumbImage: inactiveThumbImage,
|
inactiveThumbImage: inactiveThumbImage,
|
||||||
|
onInactiveThumbImageError: onInactiveThumbImageError,
|
||||||
activeTrackColor: activeTrackColor,
|
activeTrackColor: activeTrackColor,
|
||||||
inactiveTrackColor: inactiveTrackColor,
|
inactiveTrackColor: inactiveTrackColor,
|
||||||
configuration: configuration,
|
configuration: configuration,
|
||||||
@ -442,7 +467,9 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
|
|||||||
..hoverColor = hoverColor
|
..hoverColor = hoverColor
|
||||||
..focusColor = focusColor
|
..focusColor = focusColor
|
||||||
..activeThumbImage = activeThumbImage
|
..activeThumbImage = activeThumbImage
|
||||||
|
..onActiveThumbImageError = onActiveThumbImageError
|
||||||
..inactiveThumbImage = inactiveThumbImage
|
..inactiveThumbImage = inactiveThumbImage
|
||||||
|
..onInactiveThumbImageError = onInactiveThumbImageError
|
||||||
..activeTrackColor = activeTrackColor
|
..activeTrackColor = activeTrackColor
|
||||||
..inactiveTrackColor = inactiveTrackColor
|
..inactiveTrackColor = inactiveTrackColor
|
||||||
..configuration = configuration
|
..configuration = configuration
|
||||||
@ -464,7 +491,9 @@ class _RenderSwitch extends RenderToggleable {
|
|||||||
Color hoverColor,
|
Color hoverColor,
|
||||||
Color focusColor,
|
Color focusColor,
|
||||||
ImageProvider activeThumbImage,
|
ImageProvider activeThumbImage,
|
||||||
|
ImageErrorListener onActiveThumbImageError,
|
||||||
ImageProvider inactiveThumbImage,
|
ImageProvider inactiveThumbImage,
|
||||||
|
ImageErrorListener onInactiveThumbImageError,
|
||||||
Color activeTrackColor,
|
Color activeTrackColor,
|
||||||
Color inactiveTrackColor,
|
Color inactiveTrackColor,
|
||||||
ImageConfiguration configuration,
|
ImageConfiguration configuration,
|
||||||
@ -477,7 +506,9 @@ class _RenderSwitch extends RenderToggleable {
|
|||||||
@required this.state,
|
@required this.state,
|
||||||
}) : assert(textDirection != null),
|
}) : assert(textDirection != null),
|
||||||
_activeThumbImage = activeThumbImage,
|
_activeThumbImage = activeThumbImage,
|
||||||
|
_onActiveThumbImageError = onActiveThumbImageError,
|
||||||
_inactiveThumbImage = inactiveThumbImage,
|
_inactiveThumbImage = inactiveThumbImage,
|
||||||
|
_onInactiveThumbImageError = onInactiveThumbImageError,
|
||||||
_activeTrackColor = activeTrackColor,
|
_activeTrackColor = activeTrackColor,
|
||||||
_inactiveTrackColor = inactiveTrackColor,
|
_inactiveTrackColor = inactiveTrackColor,
|
||||||
_configuration = configuration,
|
_configuration = configuration,
|
||||||
@ -511,6 +542,16 @@ class _RenderSwitch extends RenderToggleable {
|
|||||||
markNeedsPaint();
|
markNeedsPaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImageErrorListener get onActiveThumbImageError => _onActiveThumbImageError;
|
||||||
|
ImageErrorListener _onActiveThumbImageError;
|
||||||
|
set onActiveThumbImageError(ImageErrorListener value) {
|
||||||
|
if (value == _onActiveThumbImageError) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_onActiveThumbImageError = value;
|
||||||
|
markNeedsPaint();
|
||||||
|
}
|
||||||
|
|
||||||
ImageProvider get inactiveThumbImage => _inactiveThumbImage;
|
ImageProvider get inactiveThumbImage => _inactiveThumbImage;
|
||||||
ImageProvider _inactiveThumbImage;
|
ImageProvider _inactiveThumbImage;
|
||||||
set inactiveThumbImage(ImageProvider value) {
|
set inactiveThumbImage(ImageProvider value) {
|
||||||
@ -520,6 +561,16 @@ class _RenderSwitch extends RenderToggleable {
|
|||||||
markNeedsPaint();
|
markNeedsPaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImageErrorListener get onInactiveThumbImageError => _onInactiveThumbImageError;
|
||||||
|
ImageErrorListener _onInactiveThumbImageError;
|
||||||
|
set onInactiveThumbImageError(ImageErrorListener value) {
|
||||||
|
if (value == _onInactiveThumbImageError) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_onInactiveThumbImageError = value;
|
||||||
|
markNeedsPaint();
|
||||||
|
}
|
||||||
|
|
||||||
Color get activeTrackColor => _activeTrackColor;
|
Color get activeTrackColor => _activeTrackColor;
|
||||||
Color _activeTrackColor;
|
Color _activeTrackColor;
|
||||||
set activeTrackColor(Color value) {
|
set activeTrackColor(Color value) {
|
||||||
@ -642,12 +693,13 @@ class _RenderSwitch extends RenderToggleable {
|
|||||||
|
|
||||||
Color _cachedThumbColor;
|
Color _cachedThumbColor;
|
||||||
ImageProvider _cachedThumbImage;
|
ImageProvider _cachedThumbImage;
|
||||||
|
ImageErrorListener _cachedThumbErrorListener;
|
||||||
BoxPainter _cachedThumbPainter;
|
BoxPainter _cachedThumbPainter;
|
||||||
|
|
||||||
BoxDecoration _createDefaultThumbDecoration(Color color, ImageProvider image) {
|
BoxDecoration _createDefaultThumbDecoration(Color color, ImageProvider image, ImageErrorListener errorListener) {
|
||||||
return BoxDecoration(
|
return BoxDecoration(
|
||||||
color: color,
|
color: color,
|
||||||
image: image == null ? null : DecorationImage(image: image),
|
image: image == null ? null : DecorationImage(image: image, onError: errorListener),
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
boxShadow: kElevationToShadow[1],
|
boxShadow: kElevationToShadow[1],
|
||||||
);
|
);
|
||||||
@ -698,6 +750,10 @@ class _RenderSwitch extends RenderToggleable {
|
|||||||
? (currentValue < 0.5 ? inactiveThumbImage : activeThumbImage)
|
? (currentValue < 0.5 ? inactiveThumbImage : activeThumbImage)
|
||||||
: inactiveThumbImage;
|
: inactiveThumbImage;
|
||||||
|
|
||||||
|
final ImageErrorListener thumbErrorListener = isEnabled
|
||||||
|
? (currentValue < 0.5 ? onInactiveThumbImageError : onActiveThumbImageError)
|
||||||
|
: onInactiveThumbImageError;
|
||||||
|
|
||||||
// Paint the track
|
// Paint the track
|
||||||
final Paint paint = Paint()
|
final Paint paint = Paint()
|
||||||
..color = trackColor;
|
..color = trackColor;
|
||||||
@ -721,10 +777,11 @@ class _RenderSwitch extends RenderToggleable {
|
|||||||
try {
|
try {
|
||||||
_isPainting = true;
|
_isPainting = true;
|
||||||
BoxPainter thumbPainter;
|
BoxPainter thumbPainter;
|
||||||
if (_cachedThumbPainter == null || thumbColor != _cachedThumbColor || thumbImage != _cachedThumbImage) {
|
if (_cachedThumbPainter == null || thumbColor != _cachedThumbColor || thumbImage != _cachedThumbImage || thumbErrorListener != _cachedThumbErrorListener) {
|
||||||
_cachedThumbColor = thumbColor;
|
_cachedThumbColor = thumbColor;
|
||||||
_cachedThumbImage = thumbImage;
|
_cachedThumbImage = thumbImage;
|
||||||
_cachedThumbPainter = _createDefaultThumbDecoration(thumbColor, thumbImage).createBoxPainter(_handleDecorationChanged);
|
_cachedThumbErrorListener = thumbErrorListener;
|
||||||
|
_cachedThumbPainter = _createDefaultThumbDecoration(thumbColor, thumbImage, thumbErrorListener).createBoxPainter(_handleDecorationChanged);
|
||||||
}
|
}
|
||||||
thumbPainter = _cachedThumbPainter;
|
thumbPainter = _cachedThumbPainter;
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ class DecorationImage {
|
|||||||
/// must not be null.
|
/// must not be null.
|
||||||
const DecorationImage({
|
const DecorationImage({
|
||||||
@required this.image,
|
@required this.image,
|
||||||
|
this.onError,
|
||||||
this.colorFilter,
|
this.colorFilter,
|
||||||
this.fit,
|
this.fit,
|
||||||
this.alignment = Alignment.center,
|
this.alignment = Alignment.center,
|
||||||
@ -57,6 +58,9 @@ class DecorationImage {
|
|||||||
/// application) or a [NetworkImage] (for an image obtained from the network).
|
/// application) or a [NetworkImage] (for an image obtained from the network).
|
||||||
final ImageProvider image;
|
final ImageProvider image;
|
||||||
|
|
||||||
|
/// An optional error callback for errors emitted when loading [image].
|
||||||
|
final ImageErrorListener onError;
|
||||||
|
|
||||||
/// A color filter to apply to the image before painting it.
|
/// A color filter to apply to the image before painting it.
|
||||||
final ColorFilter colorFilter;
|
final ColorFilter colorFilter;
|
||||||
|
|
||||||
@ -239,7 +243,10 @@ class DecorationImagePainter {
|
|||||||
|
|
||||||
final ImageStream newImageStream = _details.image.resolve(configuration);
|
final ImageStream newImageStream = _details.image.resolve(configuration);
|
||||||
if (newImageStream.key != _imageStream?.key) {
|
if (newImageStream.key != _imageStream?.key) {
|
||||||
final ImageStreamListener listener = ImageStreamListener(_handleImage);
|
final ImageStreamListener listener = ImageStreamListener(
|
||||||
|
_handleImage,
|
||||||
|
onError: _details.onError,
|
||||||
|
);
|
||||||
_imageStream?.removeListener(listener);
|
_imageStream?.removeListener(listener);
|
||||||
_imageStream = newImageStream;
|
_imageStream = newImageStream;
|
||||||
_imageStream.addListener(listener);
|
_imageStream.addListener(listener);
|
||||||
@ -286,7 +293,10 @@ class DecorationImagePainter {
|
|||||||
/// After this method has been called, the object is no longer usable.
|
/// After this method has been called, the object is no longer usable.
|
||||||
@mustCallSuper
|
@mustCallSuper
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_imageStream?.removeListener(ImageStreamListener(_handleImage));
|
_imageStream?.removeListener(ImageStreamListener(
|
||||||
|
_handleImage,
|
||||||
|
onError: _details.onError,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -77,7 +77,9 @@ class FadeInImage extends StatelessWidget {
|
|||||||
const FadeInImage({
|
const FadeInImage({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.placeholder,
|
@required this.placeholder,
|
||||||
|
this.placeholderErrorBuilder,
|
||||||
@required this.image,
|
@required this.image,
|
||||||
|
this.imageErrorBuilder,
|
||||||
this.excludeFromSemantics = false,
|
this.excludeFromSemantics = false,
|
||||||
this.imageSemanticLabel,
|
this.imageSemanticLabel,
|
||||||
this.fadeOutDuration = const Duration(milliseconds: 300),
|
this.fadeOutDuration = const Duration(milliseconds: 300),
|
||||||
@ -132,7 +134,9 @@ class FadeInImage extends StatelessWidget {
|
|||||||
FadeInImage.memoryNetwork({
|
FadeInImage.memoryNetwork({
|
||||||
Key key,
|
Key key,
|
||||||
@required Uint8List placeholder,
|
@required Uint8List placeholder,
|
||||||
|
this.placeholderErrorBuilder,
|
||||||
@required String image,
|
@required String image,
|
||||||
|
this.imageErrorBuilder,
|
||||||
double placeholderScale = 1.0,
|
double placeholderScale = 1.0,
|
||||||
double imageScale = 1.0,
|
double imageScale = 1.0,
|
||||||
this.excludeFromSemantics = false,
|
this.excludeFromSemantics = false,
|
||||||
@ -200,7 +204,9 @@ class FadeInImage extends StatelessWidget {
|
|||||||
FadeInImage.assetNetwork({
|
FadeInImage.assetNetwork({
|
||||||
Key key,
|
Key key,
|
||||||
@required String placeholder,
|
@required String placeholder,
|
||||||
|
this.placeholderErrorBuilder,
|
||||||
@required String image,
|
@required String image,
|
||||||
|
this.imageErrorBuilder,
|
||||||
AssetBundle bundle,
|
AssetBundle bundle,
|
||||||
double placeholderScale,
|
double placeholderScale,
|
||||||
double imageScale = 1.0,
|
double imageScale = 1.0,
|
||||||
@ -239,9 +245,24 @@ class FadeInImage extends StatelessWidget {
|
|||||||
/// Image displayed while the target [image] is loading.
|
/// Image displayed while the target [image] is loading.
|
||||||
final ImageProvider placeholder;
|
final ImageProvider placeholder;
|
||||||
|
|
||||||
|
/// A builder function that is called if an error occurs during placeholder
|
||||||
|
/// image loading.
|
||||||
|
///
|
||||||
|
/// If this builder is not provided, any exceptions will be reported to
|
||||||
|
/// [FlutterError.onError]. If it is provided, the caller should either handle
|
||||||
|
/// the exception by providing a replacement widget, or rethrow the exception.
|
||||||
|
final ImageErrorWidgetBuilder placeholderErrorBuilder;
|
||||||
|
|
||||||
/// The target image that is displayed once it has loaded.
|
/// The target image that is displayed once it has loaded.
|
||||||
final ImageProvider image;
|
final ImageProvider image;
|
||||||
|
|
||||||
|
/// A builder function that is called if an error occurs during image loading.
|
||||||
|
///
|
||||||
|
/// If this builder is not provided, any exceptions will be reported to
|
||||||
|
/// [FlutterError.onError]. If it is provided, the caller should either handle
|
||||||
|
/// the exception by providing a replacement widget, or rethrow the exception.
|
||||||
|
final ImageErrorWidgetBuilder imageErrorBuilder;
|
||||||
|
|
||||||
/// The duration of the fade-out animation for the [placeholder].
|
/// The duration of the fade-out animation for the [placeholder].
|
||||||
final Duration fadeOutDuration;
|
final Duration fadeOutDuration;
|
||||||
|
|
||||||
@ -337,11 +358,13 @@ class FadeInImage extends StatelessWidget {
|
|||||||
|
|
||||||
Image _image({
|
Image _image({
|
||||||
@required ImageProvider image,
|
@required ImageProvider image,
|
||||||
|
ImageErrorWidgetBuilder errorBuilder,
|
||||||
ImageFrameBuilder frameBuilder,
|
ImageFrameBuilder frameBuilder,
|
||||||
}) {
|
}) {
|
||||||
assert(image != null);
|
assert(image != null);
|
||||||
return Image(
|
return Image(
|
||||||
image: image,
|
image: image,
|
||||||
|
errorBuilder: errorBuilder,
|
||||||
frameBuilder: frameBuilder,
|
frameBuilder: frameBuilder,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
@ -358,12 +381,13 @@ class FadeInImage extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget result = _image(
|
Widget result = _image(
|
||||||
image: image,
|
image: image,
|
||||||
|
errorBuilder: imageErrorBuilder,
|
||||||
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
|
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
|
||||||
if (wasSynchronouslyLoaded)
|
if (wasSynchronouslyLoaded)
|
||||||
return child;
|
return child;
|
||||||
return _AnimatedFadeOutFadeIn(
|
return _AnimatedFadeOutFadeIn(
|
||||||
target: child,
|
target: child,
|
||||||
placeholder: _image(image: placeholder),
|
placeholder: _image(image: placeholder, errorBuilder: placeholderErrorBuilder),
|
||||||
isTargetLoaded: frame != null,
|
isTargetLoaded: frame != null,
|
||||||
fadeInDuration: fadeInDuration,
|
fadeInDuration: fadeInDuration,
|
||||||
fadeOutDuration: fadeOutDuration,
|
fadeOutDuration: fadeOutDuration,
|
||||||
|
@ -40,6 +40,22 @@ class SynchronousTestImageProvider extends ImageProvider<int> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SynchronousErrorTestImageProvider extends ImageProvider<int> {
|
||||||
|
const SynchronousErrorTestImageProvider(this.throwable);
|
||||||
|
|
||||||
|
final Object throwable;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> obtainKey(ImageConfiguration configuration) {
|
||||||
|
throw throwable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ImageStreamCompleter load(int key, DecoderCallback decode) {
|
||||||
|
throw throwable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class AsyncTestImageProvider extends ImageProvider<int> {
|
class AsyncTestImageProvider extends ImageProvider<int> {
|
||||||
@override
|
@override
|
||||||
Future<int> obtainKey(ImageConfiguration configuration) {
|
Future<int> obtainKey(ImageConfiguration configuration) {
|
||||||
@ -269,6 +285,26 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('DecorationImage - error listener', () async {
|
||||||
|
String exception;
|
||||||
|
final DecorationImage backgroundImage = DecorationImage(
|
||||||
|
image: const SynchronousErrorTestImageProvider('threw'),
|
||||||
|
onError: (dynamic error, StackTrace stackTrace) {
|
||||||
|
exception = error as String;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
backgroundImage.createPainter(() { }).paint(
|
||||||
|
TestCanvas(),
|
||||||
|
Rect.largest,
|
||||||
|
Path(),
|
||||||
|
ImageConfiguration.empty,
|
||||||
|
);
|
||||||
|
// Yield so that the exception callback gets called before we check it.
|
||||||
|
await null;
|
||||||
|
expect(exception, 'threw');
|
||||||
|
});
|
||||||
|
|
||||||
test('BoxDecoration.lerp - shapes', () {
|
test('BoxDecoration.lerp - shapes', () {
|
||||||
// We don't lerp the shape, we just switch from one to the other at t=0.5.
|
// We don't lerp the shape, we just switch from one to the other at t=0.5.
|
||||||
// (Use a ShapeDecoration and ShapeBorder if you want to lerp the shapes...)
|
// (Use a ShapeDecoration and ShapeBorder if you want to lerp the shapes...)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user