From 6a5603a116088b95ea0c04528cbc3b18e36a41cd Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Tue, 14 Apr 2020 13:20:51 +0900 Subject: [PATCH] scrolling to entry with custom sliver list --- .../album/grid/list_section_layout.dart | 41 +++++++++++++++++-- lib/widgets/album/grid/scaling.dart | 16 ++++---- lib/widgets/album/thumbnail_collection.dart | 18 ++++---- 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/lib/widgets/album/grid/list_section_layout.dart b/lib/widgets/album/grid/list_section_layout.dart index 42e981131..5e5d8aaaa 100644 --- a/lib/widgets/album/grid/list_section_layout.dart +++ b/lib/widgets/album/grid/list_section_layout.dart @@ -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 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 { diff --git a/lib/widgets/album/grid/scaling.dart b/lib/widgets/album/grid/scaling.dart index c454038fa..b0248d8dd 100644 --- a/lib/widgets/album/grid/scaling.dart +++ b/lib/widgets/album/grid/scaling.dart @@ -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 { ValueNotifier _scaledExtentNotifier; OverlayEntry _overlayEntry; ThumbnailMetadata _metadata; - RenderSliver _renderSliver; RenderViewport _renderViewport; ValueNotifier get tileExtentNotifier => widget.extentNotifier; @@ -56,7 +57,6 @@ class _GridScaleGestureDetectorState extends State { final renderMetaData = firstOf(result); // abort if we cannot find an image to show on overlay if (renderMetaData == null) return; - _renderSliver = firstOf(result); _renderViewport = firstOf(result); _metadata = renderMetaData.metaData; _startExtent = tileExtentNotifier.value; @@ -105,18 +105,18 @@ class _GridScaleGestureDetectorState extends State { // 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(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, diff --git a/lib/widgets/album/thumbnail_collection.dart b/lib/widgets/album/thumbnail_collection.dart index 4497ab8b4..4d2d4af88 100644 --- a/lib/widgets/album/thumbnail_collection.dart +++ b/lib/widgets/album/thumbnail_collection.dart @@ -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( 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; }, ); },