Improve scolling performance
This commit is contained in:
parent
1d46c99154
commit
7c570c636d
2 changed files with 41 additions and 61 deletions
|
@ -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);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Reference in a new issue