scrolling to entry with custom sliver list
This commit is contained in:
parent
4edc2bf5d4
commit
6a5603a116
3 changed files with 54 additions and 21 deletions
|
@ -1,18 +1,18 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/collection_lens.dart';
|
||||
import 'package:aves/model/image_entry.dart';
|
||||
import 'package:aves/widgets/album/grid/header_generic.dart';
|
||||
import 'package:aves/widgets/album/grid/list_sliver.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class SectionedListLayoutProvider extends StatelessWidget {
|
||||
final Widget child;
|
||||
|
||||
final CollectionLens collection;
|
||||
final int columnCount;
|
||||
final double scrollableWidth;
|
||||
final double tileExtent;
|
||||
final Widget child;
|
||||
|
||||
SectionedListLayoutProvider({
|
||||
@required this.collection,
|
||||
|
@ -64,7 +64,12 @@ class SectionedListLayoutProvider extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
});
|
||||
return SectionedListLayout(sectionLayouts);
|
||||
return SectionedListLayout(
|
||||
collection: collection,
|
||||
columnCount: columnCount,
|
||||
tileExtent: tileExtent,
|
||||
sectionLayouts: sectionLayouts,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInSection(int sectionChildIndex, CollectionLens collection, dynamic sectionKey) {
|
||||
|
@ -100,9 +105,37 @@ class SectionedListLayoutProvider extends StatelessWidget {
|
|||
}
|
||||
|
||||
class SectionedListLayout {
|
||||
final CollectionLens collection;
|
||||
final int columnCount;
|
||||
final double tileExtent;
|
||||
final List<SectionLayout> sectionLayouts;
|
||||
|
||||
const SectionedListLayout(this.sectionLayouts);
|
||||
const SectionedListLayout({
|
||||
@required this.collection,
|
||||
@required this.columnCount,
|
||||
@required this.tileExtent,
|
||||
@required this.sectionLayouts,
|
||||
});
|
||||
|
||||
Rect getTileRect(ImageEntry entry) {
|
||||
final section = collection.sections.entries.firstWhere((kv) => kv.value.contains(entry), orElse: () => null);
|
||||
if (section == null) return null;
|
||||
|
||||
final sectionKey = section.key;
|
||||
final sectionLayout = sectionLayouts.firstWhere((sl) => sl.sectionKey == sectionKey, orElse: () => null);
|
||||
if (sectionLayout == null) return null;
|
||||
|
||||
final showHeaders = collection.showHeaders;
|
||||
final sectionEntryIndex = section.value.indexOf(entry);
|
||||
final column = sectionEntryIndex % columnCount;
|
||||
final row = (sectionEntryIndex / columnCount).floor();
|
||||
final listIndex = sectionLayout.firstIndex + (showHeaders ? 1 : 0) + row;
|
||||
|
||||
final left = tileExtent * column;
|
||||
final top = sectionLayout.indexToLayoutOffset(listIndex);
|
||||
debugPrint('TLAD getTileRect sectionKey=$sectionKey sectionOffset=${sectionLayout.minOffset} top=$top row=$row column=$column for title=${entry.bestTitle}');
|
||||
return Rect.fromLTWH(left, top, tileExtent, tileExtent);
|
||||
}
|
||||
}
|
||||
|
||||
class SectionLayout {
|
||||
|
|
|
@ -2,12 +2,14 @@ import 'dart:math';
|
|||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:aves/model/image_entry.dart';
|
||||
import 'package:aves/widgets/album/grid/list_section_layout.dart';
|
||||
import 'package:aves/widgets/album/grid/list_sliver.dart';
|
||||
import 'package:aves/widgets/album/grid/tile_extent_manager.dart';
|
||||
import 'package:aves/widgets/album/thumbnail.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:provider/provider.dart';
|
||||
|
||||
class GridScaleGestureDetector extends StatefulWidget {
|
||||
final GlobalKey scrollableKey;
|
||||
|
@ -33,7 +35,6 @@ class _GridScaleGestureDetectorState extends State<GridScaleGestureDetector> {
|
|||
ValueNotifier<double> _scaledExtentNotifier;
|
||||
OverlayEntry _overlayEntry;
|
||||
ThumbnailMetadata _metadata;
|
||||
RenderSliver _renderSliver;
|
||||
RenderViewport _renderViewport;
|
||||
|
||||
ValueNotifier<double> get tileExtentNotifier => widget.extentNotifier;
|
||||
|
@ -56,7 +57,6 @@ 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<RenderSliver>(result);
|
||||
_renderViewport = firstOf<RenderViewport>(result);
|
||||
_metadata = renderMetaData.metaData;
|
||||
_startExtent = tileExtentNotifier.value;
|
||||
|
@ -105,18 +105,18 @@ class _GridScaleGestureDetectorState extends State<GridScaleGestureDetector> {
|
|||
|
||||
// TODO TLAD fix scroll to specific thumbnail with custom SliverList
|
||||
// scroll to show the focal point thumbnail at its new position
|
||||
final sliverClosure = _renderSliver;
|
||||
final viewportClosure = _renderViewport;
|
||||
final index = _metadata.index;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final scrollableContext = widget.scrollableKey.currentContext;
|
||||
final gridSize = (scrollableContext.findRenderObject() as RenderBox).size;
|
||||
final newColumnCount = gridSize.width / newExtent;
|
||||
final row = index ~/ newColumnCount;
|
||||
final sectionLayout = Provider.of<SectionedListLayout>(context, listen: false);
|
||||
final tileRect = sectionLayout.getTileRect(_metadata.entry);
|
||||
final scrollOffset = (tileRect?.top ?? 0) - gridSize.height / 2;
|
||||
viewportClosure.offset.jumpTo(scrollOffset.clamp(.0, double.infinity));
|
||||
// about scrolling & offset retrieval:
|
||||
// `Scrollable.ensureVisible` only works on already rendered objects
|
||||
// `RenderViewport.showOnScreen` can find any `RenderSliver`, but not always a `RenderMetadata`
|
||||
final scrollOffset = viewportClosure.scrollOffsetOf(sliverClosure, (row + 1) * newExtent - gridSize.height / 2);
|
||||
viewportClosure.offset.jumpTo(scrollOffset.clamp(.0, double.infinity));
|
||||
// `RenderViewport.scrollOffsetOf` is a good alternative
|
||||
});
|
||||
},
|
||||
child: widget.child,
|
||||
|
|
|
@ -44,23 +44,23 @@ class ThumbnailCollection extends StatelessWidget {
|
|||
builder: (context, collection, child) {
|
||||
final scrollView = _buildScrollView(collection);
|
||||
final draggable = _buildDraggableScrollView(scrollView);
|
||||
final scaler = GridScaleGestureDetector(
|
||||
scrollableKey: _scrollableKey,
|
||||
extentNotifier: _tileExtentNotifier,
|
||||
mqSize: mqSize,
|
||||
mqHorizontalPadding: mqHorizontalPadding,
|
||||
child: draggable,
|
||||
);
|
||||
final sectionedListLayoutProvider = ValueListenableBuilder<double>(
|
||||
valueListenable: _tileExtentNotifier,
|
||||
builder: (context, tileExtent, child) => SectionedListLayoutProvider(
|
||||
collection: collection,
|
||||
scrollableWidth: mqSize.width - mqHorizontalPadding,
|
||||
tileExtent: tileExtent,
|
||||
child: draggable,
|
||||
child: scaler,
|
||||
),
|
||||
);
|
||||
final scaler = GridScaleGestureDetector(
|
||||
scrollableKey: _scrollableKey,
|
||||
extentNotifier: _tileExtentNotifier,
|
||||
mqSize: mqSize,
|
||||
mqHorizontalPadding: mqHorizontalPadding,
|
||||
child: sectionedListLayoutProvider,
|
||||
);
|
||||
return scaler;
|
||||
return sectionedListLayoutProvider;
|
||||
},
|
||||
);
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue