Improve scolling performance

This commit is contained in:
Vishnu Mohandas 2020-05-04 21:05:23 +05:30
parent 1d46c99154
commit 7c570c636d
2 changed files with 41 additions and 61 deletions

View file

@ -3,15 +3,12 @@ import 'dart:collection';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:photos/core/thumbnail_cache.dart';
import 'package:photos/models/photo.dart';
import 'package:photos/photo_loader.dart';
import 'package:photos/ui/detail_page.dart';
import 'package:photos/ui/thumbnail_widget.dart';
import 'package:photos/utils/date_time_util.dart';
import 'package:provider/provider.dart';
import 'package:visibility_detector/visibility_detector.dart';
import 'package:photos/core/constants.dart';
class Gallery extends StatefulWidget {
final List<Photo> photos;
@ -106,7 +103,7 @@ class _GalleryState extends State<Gallery> {
? Border.all(width: 4.0, color: Colors.blue)
: null,
),
child: GalleryItemWidget(photo),
child: ThumbnailWidget(photo),
),
);
}
@ -176,52 +173,3 @@ class _GalleryState extends State<Gallery> {
firstDate.day == secondDate.day;
}
}
class GalleryItemWidget extends StatefulWidget {
final Photo photo;
const GalleryItemWidget(
this.photo, {
Key key,
}) : super(key: key);
@override
_GalleryItemWidgetState createState() => _GalleryItemWidgetState();
}
class _GalleryItemWidgetState extends State<GalleryItemWidget> {
bool _isVisible = false;
bool _isLoading = false;
@override
Widget build(BuildContext context) {
return VisibilityDetector(
key: Key(widget.photo.generatedId.toString()),
child: ThumbnailWidget(widget.photo),
onVisibilityChanged: (info) {
_isVisible = info.visibleFraction == 1;
if (_isVisible && !_isLoading) {
_isLoading = true;
_scheduleCaching();
}
},
);
}
void _scheduleCaching() {
Future.delayed(Duration(milliseconds: 500), () {
if (!_isVisible) {
_isLoading = false;
return;
}
if (ThumbnailLruCache.get(widget.photo, THUMBNAIL_LARGE_SIZE) == null) {
widget.photo
.getAsset()
.thumbDataWithSize(THUMBNAIL_LARGE_SIZE, THUMBNAIL_LARGE_SIZE)
.then((data) {
ThumbnailLruCache.put(widget.photo, THUMBNAIL_LARGE_SIZE, data);
});
}
});
}
}

View file

@ -23,7 +23,8 @@ class ZoomableImage extends StatefulWidget {
class _ZoomableImageState extends State<ZoomableImage> {
ImageProvider _imageProvider;
bool _loadedThumbnail = false;
bool _loadedSmallThumbnail = false;
bool _loadedLargeThumbnail = false;
bool _loadedFinalImage = false;
ValueChanged<PhotoViewScaleState> _scaleStateChangedCallback;
@ -39,25 +40,43 @@ class _ZoomableImageState extends State<ZoomableImage> {
@override
Widget build(BuildContext context) {
if (!_loadedThumbnail && !_loadedFinalImage) {
if (!_loadedSmallThumbnail &&
!_loadedLargeThumbnail &&
!_loadedFinalImage) {
final cachedThumbnail =
ThumbnailLruCache.get(widget.photo, THUMBNAIL_SMALL_SIZE);
if (cachedThumbnail != null) {
_imageProvider = Image.memory(cachedThumbnail).image;
_loadedSmallThumbnail = true;
}
}
if (!_loadedLargeThumbnail && !_loadedFinalImage) {
final cachedThumbnail =
ThumbnailLruCache.get(widget.photo, THUMBNAIL_LARGE_SIZE);
if (cachedThumbnail != null) {
_imageProvider = Image.memory(cachedThumbnail).image;
_loadedThumbnail = true;
_onLargeThumbnailLoaded(Image.memory(cachedThumbnail).image, context);
} else {
widget.photo
.getAsset()
.thumbDataWithSize(THUMBNAIL_LARGE_SIZE, THUMBNAIL_LARGE_SIZE)
.then((data) {
_onLargeThumbnailLoaded(Image.memory(data).image, context);
ThumbnailLruCache.put(widget.photo, THUMBNAIL_LARGE_SIZE, data);
});
}
}
if (!_loadedFinalImage) {
if (ImageLruCache.get(widget.photo) != null) {
final bytes = ImageLruCache.get(widget.photo);
_onFinalImageLoaded(bytes, context);
final cachedImage = ImageLruCache.get(widget.photo);
if (cachedImage != null) {
_onFinalImageLoaded(cachedImage, context);
} else {
widget.photo.getBytes().then((bytes) {
if (mounted) {
setState(() {
ImageLruCache.put(widget.photo, bytes);
_onFinalImageLoaded(bytes, context);
ImageLruCache.put(widget.photo, bytes);
});
}
});
@ -76,6 +95,19 @@ class _ZoomableImageState extends State<ZoomableImage> {
}
}
void _onLargeThumbnailLoaded(
ImageProvider imageProvider, BuildContext context) {
precacheImage(imageProvider, context).then((value) {
if (mounted) {
setState(() {
_imageProvider = imageProvider;
_loadedLargeThumbnail = true;
});
}
});
_loadedLargeThumbnail = true;
}
void _onFinalImageLoaded(Uint8List bytes, BuildContext context) {
final imageProvider = Image.memory(bytes).image;
precacheImage(imageProvider, context).then((value) {