Info: animation between map layer with/without attribution
This commit is contained in:
parent
8e6cfec357
commit
b83986e01a
6 changed files with 28 additions and 228 deletions
|
@ -1,34 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class ComaDivider extends StatelessWidget {
|
||||
final Color color;
|
||||
final Alignment alignment;
|
||||
|
||||
const ComaDivider({
|
||||
this.color = Colors.white70,
|
||||
this.alignment = Alignment.center,
|
||||
});
|
||||
|
||||
double get peakStop => (alignment.x + 1 / 2).clamp(.02, .98);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 1,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
stops: [
|
||||
0,
|
||||
peakStop,
|
||||
1,
|
||||
],
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
color,
|
||||
Colors.transparent,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,176 +0,0 @@
|
|||
import 'dart:math' as math;
|
||||
import 'dart:ui' show lerpDouble;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
class SliverTransitionGridDelegateWithCrossAxisCount extends SliverGridDelegate {
|
||||
const SliverTransitionGridDelegateWithCrossAxisCount({
|
||||
@required this.crossAxisCount,
|
||||
this.mainAxisSpacing = 0.0,
|
||||
this.crossAxisSpacing = 0.0,
|
||||
this.childAspectRatio = 1.0,
|
||||
}) : assert(crossAxisCount != null && crossAxisCount > 0),
|
||||
assert(mainAxisSpacing != null && mainAxisSpacing >= 0),
|
||||
assert(crossAxisSpacing != null && crossAxisSpacing >= 0),
|
||||
assert(childAspectRatio != null && childAspectRatio > 0);
|
||||
|
||||
/// The number of children in the cross axis.
|
||||
final double crossAxisCount;
|
||||
|
||||
/// The number of logical pixels between each child along the main axis.
|
||||
final double mainAxisSpacing;
|
||||
|
||||
/// The number of logical pixels between each child along the cross axis.
|
||||
final double crossAxisSpacing;
|
||||
|
||||
/// The ratio of the cross-axis to the main-axis extent of each child.
|
||||
final double childAspectRatio;
|
||||
|
||||
@override
|
||||
SliverGridLayout getLayout(SliverConstraints constraints) {
|
||||
final t = crossAxisCount - crossAxisCount.truncateToDouble();
|
||||
return SliverTransitionGridTileLayout(
|
||||
current: _buildSettings(constraints, crossAxisCount),
|
||||
floor: t != 0 ? _buildSettings(constraints, crossAxisCount.floorToDouble()) : null,
|
||||
ceil: t != 0 ? _buildSettings(constraints, crossAxisCount.ceilToDouble()) : null,
|
||||
t: t,
|
||||
reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection),
|
||||
);
|
||||
}
|
||||
|
||||
SliverTransitionGridTileLayoutSettings _buildSettings(SliverConstraints constraints, double crossAxisCount) {
|
||||
final usableCrossAxisExtent = constraints.crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1);
|
||||
final childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount;
|
||||
final childMainAxisExtent = childCrossAxisExtent / childAspectRatio;
|
||||
final current = SliverTransitionGridTileLayoutSettings(
|
||||
crossAxisCount: crossAxisCount,
|
||||
mainAxisStride: childMainAxisExtent + mainAxisSpacing,
|
||||
crossAxisStride: childCrossAxisExtent + crossAxisSpacing,
|
||||
childMainAxisExtent: childMainAxisExtent,
|
||||
childCrossAxisExtent: childCrossAxisExtent,
|
||||
);
|
||||
return current;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRelayout(SliverTransitionGridDelegateWithCrossAxisCount oldDelegate) {
|
||||
return oldDelegate.crossAxisCount != crossAxisCount || oldDelegate.mainAxisSpacing != mainAxisSpacing || oldDelegate.crossAxisSpacing != crossAxisSpacing || oldDelegate.childAspectRatio != childAspectRatio;
|
||||
}
|
||||
}
|
||||
|
||||
class SliverTransitionGridTileLayoutSettings {
|
||||
final double crossAxisCount;
|
||||
|
||||
/// The number of pixels from the leading edge of one tile to the leading edge
|
||||
/// of the next tile in the main axis.
|
||||
final double mainAxisStride;
|
||||
|
||||
/// The number of pixels from the leading edge of one tile to the leading edge
|
||||
/// of the next tile in the cross axis.
|
||||
final double crossAxisStride;
|
||||
|
||||
/// The number of pixels from the leading edge of one tile to the trailing
|
||||
/// edge of the same tile in the main axis.
|
||||
final double childMainAxisExtent;
|
||||
|
||||
/// The number of pixels from the leading edge of one tile to the trailing
|
||||
/// edge of the same tile in the cross axis.
|
||||
final double childCrossAxisExtent;
|
||||
|
||||
const SliverTransitionGridTileLayoutSettings({
|
||||
@required this.crossAxisCount,
|
||||
@required this.mainAxisStride,
|
||||
@required this.crossAxisStride,
|
||||
@required this.childMainAxisExtent,
|
||||
@required this.childCrossAxisExtent,
|
||||
}) : assert(crossAxisCount != null && crossAxisCount > 0),
|
||||
assert(mainAxisStride != null && mainAxisStride >= 0),
|
||||
assert(crossAxisStride != null && crossAxisStride >= 0),
|
||||
assert(childMainAxisExtent != null && childMainAxisExtent >= 0),
|
||||
assert(childCrossAxisExtent != null && childCrossAxisExtent >= 0);
|
||||
}
|
||||
|
||||
class SliverTransitionGridTileLayout extends SliverGridLayout {
|
||||
/// Creates a layout that uses equally sized and spaced tiles.
|
||||
///
|
||||
/// All of the arguments must not be null and must not be negative. The
|
||||
/// `crossAxisCount` argument must be greater than zero.
|
||||
const SliverTransitionGridTileLayout({
|
||||
@required this.current,
|
||||
this.floor,
|
||||
this.ceil,
|
||||
this.t = 0,
|
||||
@required this.reverseCrossAxis,
|
||||
}) : assert(reverseCrossAxis != null);
|
||||
|
||||
final SliverTransitionGridTileLayoutSettings current, floor, ceil;
|
||||
final double t;
|
||||
|
||||
/// Whether the children should be placed in the opposite order of increasing
|
||||
/// coordinates in the cross axis.
|
||||
///
|
||||
/// For example, if the cross axis is horizontal, the children are placed from
|
||||
/// left to right when [reverseCrossAxis] is false and from right to left when
|
||||
/// [reverseCrossAxis] is true.
|
||||
///
|
||||
/// Typically set to the return value of [axisDirectionIsReversed] applied to
|
||||
/// the [SliverConstraints.crossAxisDirection].
|
||||
final bool reverseCrossAxis;
|
||||
|
||||
@override
|
||||
int getMinChildIndexForScrollOffset(double scrollOffset) {
|
||||
final settings = t == 0 ? current : floor;
|
||||
final index = settings.mainAxisStride > 0.0 ? (settings.crossAxisCount * (scrollOffset ~/ settings.mainAxisStride)).floor() : 0;
|
||||
return index;
|
||||
}
|
||||
|
||||
@override
|
||||
int getMaxChildIndexForScrollOffset(double scrollOffset) {
|
||||
final settings = t == 0 ? current : floor;
|
||||
if (settings.mainAxisStride > 0.0) {
|
||||
final mainAxisCount = (scrollOffset / settings.mainAxisStride).ceil();
|
||||
final index = math.max(0, settings.crossAxisCount * mainAxisCount - 1).ceil();
|
||||
return index;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
double _getScrollOffset(int index, SliverTransitionGridTileLayoutSettings settings) {
|
||||
return (index ~/ settings.crossAxisCount) * settings.mainAxisStride;
|
||||
}
|
||||
|
||||
double _getCrossAxisOffset(int index, SliverTransitionGridTileLayoutSettings settings) {
|
||||
final crossAxisStart = (index % settings.crossAxisCount) * settings.crossAxisStride;
|
||||
if (reverseCrossAxis) {
|
||||
return settings.crossAxisCount * settings.crossAxisStride - crossAxisStart - settings.childCrossAxisExtent - (settings.crossAxisStride - settings.childCrossAxisExtent);
|
||||
}
|
||||
return crossAxisStart;
|
||||
}
|
||||
|
||||
@override
|
||||
SliverGridGeometry getGeometryForChildIndex(int index) {
|
||||
return SliverGridGeometry(
|
||||
scrollOffset: t == 0 ? _getScrollOffset(index, current) : lerpDouble(_getScrollOffset(index, floor), _getScrollOffset(index, ceil), t),
|
||||
crossAxisOffset: t == 0 ? _getCrossAxisOffset(index, current) : lerpDouble(_getCrossAxisOffset(index, floor), _getCrossAxisOffset(index, ceil), t),
|
||||
mainAxisExtent: current.childMainAxisExtent,
|
||||
crossAxisExtent: current.childCrossAxisExtent,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
double computeMaxScrollOffset(int childCount) {
|
||||
assert(childCount != null);
|
||||
|
||||
if (t != 0) {
|
||||
final index = childCount - 1;
|
||||
final maxScrollOffset = lerpDouble(_getScrollOffset(index, floor), _getScrollOffset(index, ceil), t) + current.mainAxisStride;
|
||||
return maxScrollOffset;
|
||||
}
|
||||
|
||||
final mainAxisCount = ((childCount - 1) ~/ current.crossAxisCount) + 1;
|
||||
final mainAxisSpacing = current.mainAxisStride - current.childMainAxisExtent;
|
||||
final maxScrollOffset = current.mainAxisStride * mainAxisCount - mainAxisSpacing;
|
||||
return maxScrollOffset;
|
||||
}
|
||||
}
|
|
@ -28,6 +28,9 @@ class Durations {
|
|||
static const fullscreenPageAnimation = Duration(milliseconds: 300);
|
||||
static const fullscreenOverlayAnimation = Duration(milliseconds: 200);
|
||||
|
||||
// info
|
||||
static const mapStyleSwitchAnimation = Duration(milliseconds: 300);
|
||||
|
||||
// delays & refresh intervals
|
||||
static const opToastDisplay = Duration(seconds: 2);
|
||||
static const collectionScrollMonitoringTimerDelay = Duration(milliseconds: 100);
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'package:aves/model/image_entry.dart';
|
|||
import 'package:aves/model/settings/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/utils/durations.dart';
|
||||
import 'package:aves/widgets/common/aves_filter_chip.dart';
|
||||
import 'package:aves/widgets/common/icons.dart';
|
||||
import 'package:aves/widgets/fullscreen/info/common.dart';
|
||||
|
@ -32,7 +33,7 @@ class LocationSection extends StatefulWidget {
|
|||
_LocationSectionState createState() => _LocationSectionState();
|
||||
}
|
||||
|
||||
class _LocationSectionState extends State<LocationSection> {
|
||||
class _LocationSectionState extends State<LocationSection> with SingleTickerProviderStateMixin {
|
||||
String _loadedUri;
|
||||
|
||||
static const extent = 48.0;
|
||||
|
@ -106,6 +107,11 @@ class _LocationSectionState extends State<LocationSection> {
|
|||
if (notification is MapStyleChangedNotification) setState(() {});
|
||||
return false;
|
||||
},
|
||||
child: AnimatedSize(
|
||||
alignment: Alignment.topCenter,
|
||||
curve: Curves.easeInOutCubic,
|
||||
duration: Durations.mapStyleSwitchAnimation,
|
||||
vsync: this,
|
||||
child: settings.infoMapStyle.isGoogleMaps
|
||||
? EntryGoogleMap(
|
||||
latLng: entry.latLng,
|
||||
|
@ -123,6 +129,7 @@ class _LocationSectionState extends State<LocationSection> {
|
|||
markerBuilder: buildMarker,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (entry.hasGps)
|
||||
InfoRowGroup(Map.fromEntries([
|
||||
MapEntry('Coordinates', settings.coordinateFormat.format(entry.latLng)),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/labs/outlined_text.dart';
|
||||
import 'package:aves/widgets/common/fx/outlined_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_map/plugin_api.dart';
|
||||
|
|
Loading…
Reference in a new issue