use cached image during hero animation if possible
This commit is contained in:
parent
142b4a5ade
commit
09cef69d10
3 changed files with 30 additions and 10 deletions
|
@ -4,6 +4,7 @@ import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/utils/constants.dart';
|
import 'package:aves/utils/constants.dart';
|
||||||
import 'package:aves/widgets/common/icons.dart';
|
import 'package:aves/widgets/common/icons.dart';
|
||||||
import 'package:aves/widgets/common/image_providers/thumbnail_provider.dart';
|
import 'package:aves/widgets/common/image_providers/thumbnail_provider.dart';
|
||||||
|
import 'package:aves/widgets/common/image_providers/uri_image_provider.dart';
|
||||||
import 'package:aves/widgets/common/image_providers/uri_picture_provider.dart';
|
import 'package:aves/widgets/common/image_providers/uri_picture_provider.dart';
|
||||||
import 'package:aves/widgets/common/transition_image.dart';
|
import 'package:aves/widgets/common/transition_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -49,9 +50,9 @@ class Thumbnail extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildRasterImage() {
|
Widget _buildRasterImage() {
|
||||||
final provider = ThumbnailProvider(entry: entry, extent: Constants.thumbnailCacheExtent);
|
final thumbnailProvider = ThumbnailProvider(entry: entry, extent: Constants.thumbnailCacheExtent);
|
||||||
final image = Image(
|
final image = Image(
|
||||||
image: provider,
|
image: thumbnailProvider,
|
||||||
width: extent,
|
width: extent,
|
||||||
height: extent,
|
height: extent,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
|
@ -61,8 +62,18 @@ class Thumbnail extends StatelessWidget {
|
||||||
: Hero(
|
: Hero(
|
||||||
tag: heroTag,
|
tag: heroTag,
|
||||||
flightShuttleBuilder: (flight, animation, direction, fromHero, toHero) {
|
flightShuttleBuilder: (flight, animation, direction, fromHero, toHero) {
|
||||||
|
ImageProvider heroImageProvider = thumbnailProvider;
|
||||||
|
if (!entry.isVideo && !entry.isSvg) {
|
||||||
|
final imageProvider = UriImage(
|
||||||
|
uri: entry.uri,
|
||||||
|
mimeType: entry.mimeType,
|
||||||
|
);
|
||||||
|
if (imageCache.statusForKey(imageProvider).keepAlive) {
|
||||||
|
heroImageProvider = imageProvider;
|
||||||
|
}
|
||||||
|
}
|
||||||
return TransitionImage(
|
return TransitionImage(
|
||||||
image: provider,
|
image: heroImageProvider,
|
||||||
animation: animation,
|
animation: animation,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -159,6 +159,8 @@ class _TransitionImagePainter extends CustomPainter {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
|
if (image == null) return;
|
||||||
|
|
||||||
final paint = Paint()
|
final paint = Paint()
|
||||||
..isAntiAlias = false
|
..isAntiAlias = false
|
||||||
..filterQuality = FilterQuality.low;
|
..filterQuality = FilterQuality.low;
|
||||||
|
|
|
@ -54,7 +54,7 @@ class ImageView extends StatelessWidget {
|
||||||
// if the hero tag wraps the whole `PhotoView` and the `loadingBuilder` is not provided,
|
// if the hero tag wraps the whole `PhotoView` and the `loadingBuilder` is not provided,
|
||||||
// there's a black frame between the hero animation and the final image, even when it's cached.
|
// there's a black frame between the hero animation and the final image, even when it's cached.
|
||||||
|
|
||||||
final loadingBuilder = (context) => Center(
|
final thumbnailLoadingBuilder = (context) => Center(
|
||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
// enforce original aspect ratio, as some thumbnails aspect ratios slightly differ
|
// enforce original aspect ratio, as some thumbnails aspect ratios slightly differ
|
||||||
aspectRatio: entry.displayAspectRatio,
|
aspectRatio: entry.displayAspectRatio,
|
||||||
|
@ -77,7 +77,7 @@ class ImageView extends StatelessWidget {
|
||||||
mimeType: entry.mimeType,
|
mimeType: entry.mimeType,
|
||||||
colorFilter: Constants.svgColorFilter,
|
colorFilter: Constants.svgColorFilter,
|
||||||
),
|
),
|
||||||
placeholderBuilder: loadingBuilder,
|
placeholderBuilder: thumbnailLoadingBuilder,
|
||||||
),
|
),
|
||||||
backgroundDecoration: backgroundDecoration,
|
backgroundDecoration: backgroundDecoration,
|
||||||
scaleStateChangedCallback: onScaleChanged,
|
scaleStateChangedCallback: onScaleChanged,
|
||||||
|
@ -86,14 +86,21 @@ class ImageView extends StatelessWidget {
|
||||||
onTapUp: (tapContext, details, value) => onTap?.call(),
|
onTapUp: (tapContext, details, value) => onTap?.call(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
final uriImage = UriImage(
|
||||||
|
uri: entry.uri,
|
||||||
|
mimeType: entry.mimeType,
|
||||||
|
);
|
||||||
child = PhotoView(
|
child = PhotoView(
|
||||||
// key includes size and orientation to refresh when the image is rotated
|
// key includes size and orientation to refresh when the image is rotated
|
||||||
key: ValueKey('${entry.orientationDegrees}_${entry.width}_${entry.height}_${entry.path}'),
|
key: ValueKey('${entry.orientationDegrees}_${entry.width}_${entry.height}_${entry.path}'),
|
||||||
imageProvider: UriImage(
|
imageProvider: uriImage,
|
||||||
uri: entry.uri,
|
// when the full image is ready, we use it in the `loadingBuilder`
|
||||||
mimeType: entry.mimeType,
|
// we still provide a `loadingBuilder` in that case to avoid a black frame after hero animation
|
||||||
),
|
loadingBuilder: (context, event) => imageCache.statusForKey(uriImage).keepAlive
|
||||||
loadingBuilder: (context, event) => loadingBuilder(context),
|
? Image(
|
||||||
|
image: uriImage,
|
||||||
|
)
|
||||||
|
: thumbnailLoadingBuilder(context),
|
||||||
backgroundDecoration: backgroundDecoration,
|
backgroundDecoration: backgroundDecoration,
|
||||||
scaleStateChangedCallback: onScaleChanged,
|
scaleStateChangedCallback: onScaleChanged,
|
||||||
minScale: PhotoViewComputedScale.contained,
|
minScale: PhotoViewComputedScale.contained,
|
||||||
|
|
Loading…
Reference in a new issue