use SliverList instead of multiple SliverGrid + SliverStickyHeader

This commit is contained in:
Thibault Deckers 2020-04-10 11:07:18 +09:00
parent 802efda6be
commit 0cec7af363
5 changed files with 106 additions and 70 deletions

View 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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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:

View file

@ -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: