use cached image during hero animation if possible

This commit is contained in:
Thibault Deckers 2020-04-03 10:59:16 +09:00
parent 142b4a5ade
commit 09cef69d10
3 changed files with 30 additions and 10 deletions

View file

@ -4,6 +4,7 @@ import 'package:aves/model/image_entry.dart';
import 'package:aves/utils/constants.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/uri_image_provider.dart';
import 'package:aves/widgets/common/image_providers/uri_picture_provider.dart';
import 'package:aves/widgets/common/transition_image.dart';
import 'package:flutter/material.dart';
@ -49,9 +50,9 @@ class Thumbnail extends StatelessWidget {
}
Widget _buildRasterImage() {
final provider = ThumbnailProvider(entry: entry, extent: Constants.thumbnailCacheExtent);
final thumbnailProvider = ThumbnailProvider(entry: entry, extent: Constants.thumbnailCacheExtent);
final image = Image(
image: provider,
image: thumbnailProvider,
width: extent,
height: extent,
fit: BoxFit.cover,
@ -61,8 +62,18 @@ class Thumbnail extends StatelessWidget {
: Hero(
tag: heroTag,
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(
image: provider,
image: heroImageProvider,
animation: animation,
);
},

View file

@ -159,6 +159,8 @@ class _TransitionImagePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
if (image == null) return;
final paint = Paint()
..isAntiAlias = false
..filterQuality = FilterQuality.low;

View file

@ -54,7 +54,7 @@ class ImageView extends StatelessWidget {
// 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.
final loadingBuilder = (context) => Center(
final thumbnailLoadingBuilder = (context) => Center(
child: AspectRatio(
// enforce original aspect ratio, as some thumbnails aspect ratios slightly differ
aspectRatio: entry.displayAspectRatio,
@ -77,7 +77,7 @@ class ImageView extends StatelessWidget {
mimeType: entry.mimeType,
colorFilter: Constants.svgColorFilter,
),
placeholderBuilder: loadingBuilder,
placeholderBuilder: thumbnailLoadingBuilder,
),
backgroundDecoration: backgroundDecoration,
scaleStateChangedCallback: onScaleChanged,
@ -86,14 +86,21 @@ class ImageView extends StatelessWidget {
onTapUp: (tapContext, details, value) => onTap?.call(),
);
} else {
final uriImage = UriImage(
uri: entry.uri,
mimeType: entry.mimeType,
);
child = PhotoView(
// key includes size and orientation to refresh when the image is rotated
key: ValueKey('${entry.orientationDegrees}_${entry.width}_${entry.height}_${entry.path}'),
imageProvider: UriImage(
uri: entry.uri,
mimeType: entry.mimeType,
),
loadingBuilder: (context, event) => loadingBuilder(context),
imageProvider: uriImage,
// when the full image is ready, we use it in the `loadingBuilder`
// we still provide a `loadingBuilder` in that case to avoid a black frame after hero animation
loadingBuilder: (context, event) => imageCache.statusForKey(uriImage).keepAlive
? Image(
image: uriImage,
)
: thumbnailLoadingBuilder(context),
backgroundDecoration: backgroundDecoration,
scaleStateChangedCallback: onScaleChanged,
minScale: PhotoViewComputedScale.contained,