use SliverList instead of multiple SliverGrid + SliverStickyHeader
This commit is contained in:
parent
802efda6be
commit
0cec7af363
5 changed files with 106 additions and 70 deletions
105
lib/widgets/album/collection_list_sliver.dart
Normal file
105
lib/widgets/album/collection_list_sliver.dart
Normal file
|
@ -0,0 +1,105 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/collection_lens.dart';
|
||||
import 'package:aves/widgets/album/collection_section.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// use a `SliverList` instead of multiple `SliverGrid` because having one `SliverGrid` per section does not scale up
|
||||
// with the multiple `SliverGrid` solution, thumbnails at the beginning of each sections are built even though they are offscreen
|
||||
// because of `RenderSliverMultiBoxAdaptor.addInitialChild` called by `RenderSliverGrid.performLayout` (line 547), as of Flutter v1.17.0
|
||||
class CollectionListSliver extends StatelessWidget {
|
||||
final CollectionLens collection;
|
||||
final bool showHeader;
|
||||
final int columnCount;
|
||||
final double tileExtent;
|
||||
|
||||
const CollectionListSliver({
|
||||
Key key,
|
||||
@required this.collection,
|
||||
@required this.showHeader,
|
||||
@required this.columnCount,
|
||||
@required this.tileExtent,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sectionLayouts = <_SectionLayout>[];
|
||||
final sectionKeys = collection.sections.keys.toList();
|
||||
var firstIndex = 0;
|
||||
sectionKeys.forEach((sectionKey) {
|
||||
final sectionEntryCount = collection.sections[sectionKey].length;
|
||||
final rowCount = (sectionEntryCount / columnCount).ceil();
|
||||
final widgetCount = rowCount + (showHeader ? 1 : 0);
|
||||
// closure of `firstIndex` on `sectionFirstIndex`
|
||||
final sectionFirstIndex = firstIndex;
|
||||
sectionLayouts.add(
|
||||
_SectionLayout(
|
||||
sectionKey: sectionKey,
|
||||
widgetCount: widgetCount,
|
||||
firstIndex: sectionFirstIndex,
|
||||
builder: (context, listIndex) {
|
||||
listIndex -= sectionFirstIndex;
|
||||
if (showHeader) {
|
||||
if (listIndex == 0) {
|
||||
return SectionHeader(
|
||||
collection: collection,
|
||||
sections: collection.sections,
|
||||
sectionKey: sectionKey,
|
||||
);
|
||||
}
|
||||
listIndex--;
|
||||
}
|
||||
|
||||
final section = collection.sections[sectionKey];
|
||||
final minEntryIndex = listIndex * columnCount;
|
||||
final maxEntryIndex = min(sectionEntryCount, minEntryIndex + columnCount);
|
||||
final children = <Widget>[];
|
||||
for (var i = minEntryIndex; i < maxEntryIndex; i++) {
|
||||
children.add(GridThumbnail(
|
||||
collection: collection,
|
||||
index: i,
|
||||
entry: section[i],
|
||||
tileExtent: tileExtent,
|
||||
));
|
||||
}
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: children,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
firstIndex += widgetCount;
|
||||
});
|
||||
final childCount = firstIndex;
|
||||
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index >= childCount) return null;
|
||||
final sectionLayout = sectionLayouts.firstWhere((section) => section.hasChild(index));
|
||||
return sectionLayout.builder(context, index);
|
||||
},
|
||||
childCount: childCount,
|
||||
addAutomaticKeepAlives: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SectionLayout {
|
||||
final dynamic sectionKey;
|
||||
final int widgetCount;
|
||||
final int firstIndex;
|
||||
final int lastIndex;
|
||||
final IndexedWidgetBuilder builder;
|
||||
|
||||
const _SectionLayout({
|
||||
@required this.sectionKey,
|
||||
@required this.widgetCount,
|
||||
@required this.firstIndex,
|
||||
@required this.builder,
|
||||
}) : lastIndex = firstIndex + widgetCount - 1;
|
||||
|
||||
bool hasChild(int index) => firstIndex <= index && index <= lastIndex;
|
||||
}
|
|
@ -8,7 +8,6 @@ import 'package:aves/widgets/album/tile_extent_manager.dart';
|
|||
import 'package:aves/widgets/common/data_providers/media_query_data_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
|
||||
|
||||
class GridScaleGestureDetector extends StatefulWidget {
|
||||
final GlobalKey scrollableKey;
|
||||
|
@ -53,7 +52,7 @@ class _GridScaleGestureDetectorState extends State<GridScaleGestureDetector> {
|
|||
final renderMetaData = firstOf<RenderMetaData>(result);
|
||||
// abort if we cannot find an image to show on overlay
|
||||
if (renderMetaData == null) return;
|
||||
_renderSliver = firstOf<RenderSliverStickyHeader>(result) ?? firstOf<RenderSliverGrid>(result);
|
||||
_renderSliver = firstOf<RenderSliverList>(result);
|
||||
_renderViewport = firstOf<RenderViewport>(result);
|
||||
_metadata = renderMetaData.metaData;
|
||||
_startExtent = tileExtentNotifier.value;
|
||||
|
|
|
@ -7,62 +7,6 @@ import 'package:aves/widgets/album/transparent_material_page_route.dart';
|
|||
import 'package:aves/widgets/common/icons.dart';
|
||||
import 'package:aves/widgets/fullscreen/fullscreen_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
|
||||
|
||||
class SectionSliver extends StatelessWidget {
|
||||
final CollectionLens collection;
|
||||
final dynamic sectionKey;
|
||||
final double tileExtent;
|
||||
final bool showHeader;
|
||||
|
||||
const SectionSliver({
|
||||
Key key,
|
||||
@required this.collection,
|
||||
@required this.sectionKey,
|
||||
@required this.tileExtent,
|
||||
@required this.showHeader,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sections = collection.sections;
|
||||
final sectionEntries = sections[sectionKey];
|
||||
final childCount = sectionEntries.length;
|
||||
|
||||
final sliver = SliverGrid(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
// TODO TLAD thumbnails at the beginning of each sections are built even though they are offscreen
|
||||
// because of `RenderSliverMultiBoxAdaptor.addInitialChild`
|
||||
// called by `RenderSliverGrid.performLayout` (line 547)
|
||||
(context, index) => index < childCount
|
||||
? GridThumbnail(
|
||||
collection: collection,
|
||||
index: index,
|
||||
entry: sectionEntries[index],
|
||||
tileExtent: tileExtent,
|
||||
)
|
||||
: null,
|
||||
childCount: childCount,
|
||||
addAutomaticKeepAlives: false,
|
||||
),
|
||||
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: tileExtent,
|
||||
),
|
||||
);
|
||||
|
||||
return showHeader
|
||||
? SliverStickyHeader(
|
||||
header: SectionHeader(
|
||||
collection: collection,
|
||||
sections: sections,
|
||||
sectionKey: sectionKey,
|
||||
),
|
||||
sliver: sliver,
|
||||
overlapsContent: false,
|
||||
)
|
||||
: sliver;
|
||||
}
|
||||
}
|
||||
|
||||
class GridThumbnail extends StatelessWidget {
|
||||
final CollectionLens collection;
|
||||
|
|
|
@ -136,15 +136,6 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
flutter_sticky_header:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: HEAD
|
||||
resolved-ref: "14be154f50f5d14e88cc05b93b12377012b8905a"
|
||||
url: "git://github.com/deckerst/flutter_sticky_header.git"
|
||||
source: git
|
||||
version: "0.4.2"
|
||||
flutter_svg:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
@ -30,9 +30,6 @@ dependencies:
|
|||
url: https://github.com/AndreHaueisen/flushbar.git
|
||||
ref: 13c55a8
|
||||
flutter_native_timezone:
|
||||
flutter_sticky_header:
|
||||
git:
|
||||
url: git://github.com/deckerst/flutter_sticky_header.git
|
||||
flutter_svg:
|
||||
geocoder:
|
||||
google_maps_flutter:
|
||||
|
|
Loading…
Reference in a new issue