mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-24 18:38:48 +01:00
Make app bar in home pages translucent when scrolled
This commit is contained in:
parent
10aa594057
commit
86cdc1f9c8
2 changed files with 712 additions and 1 deletions
|
@ -12,6 +12,7 @@ import 'package:nc_photos/widget/account_picker_dialog.dart';
|
|||
import 'package:nc_photos/widget/app_bar_circular_progress_indicator.dart';
|
||||
import 'package:nc_photos/widget/app_bar_title_container.dart';
|
||||
import 'package:nc_photos/widget/settings.dart';
|
||||
import 'package:nc_photos/widget/translucent_sliver_app_bar.dart';
|
||||
|
||||
/// AppBar for home screens
|
||||
class HomeSliverAppBar extends StatelessWidget {
|
||||
|
@ -27,7 +28,7 @@ class HomeSliverAppBar extends StatelessWidget {
|
|||
@override
|
||||
build(BuildContext context) {
|
||||
final accountLabel = AccountPref.of(account).getAccountLabel();
|
||||
return SliverAppBar(
|
||||
return TranslucentSliverAppBar(
|
||||
title: InkWell(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
|
@ -53,6 +54,8 @@ class HomeSliverAppBar extends StatelessWidget {
|
|||
)),
|
||||
),
|
||||
),
|
||||
scrolledUnderBackgroundColor:
|
||||
Theme.of(context).homeNavigationBarBackgroundColor,
|
||||
floating: true,
|
||||
automaticallyImplyLeading: false,
|
||||
actions: (actions ?? []) +
|
||||
|
|
708
app/lib/widget/translucent_sliver_app_bar.dart
Normal file
708
app/lib/widget/translucent_sliver_app_bar.dart
Normal file
|
@ -0,0 +1,708 @@
|
|||
// ignore_for_file: deprecated_member_use, unnecessary_null_comparison, curly_braces_in_flow_control_structures, deprecated_member_use_from_same_package
|
||||
|
||||
import 'dart:math' as math;
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// A translucent sliver app bar used in home pages
|
||||
///
|
||||
/// This calss is adopted from Flutter's SliverAppBar
|
||||
class TranslucentSliverAppBar extends StatefulWidget {
|
||||
/// Creates a material design app bar that can be placed in a [CustomScrollView].
|
||||
///
|
||||
/// The arguments [forceElevated], [primary], [floating], [pinned], [snap]
|
||||
/// and [automaticallyImplyLeading] must not be null.
|
||||
const TranslucentSliverAppBar({
|
||||
Key? key,
|
||||
this.leading,
|
||||
this.automaticallyImplyLeading = true,
|
||||
this.title,
|
||||
this.actions,
|
||||
this.flexibleSpace,
|
||||
this.bottom,
|
||||
this.elevation,
|
||||
this.shadowColor,
|
||||
this.surfaceTintColor,
|
||||
this.forceElevated = false,
|
||||
this.backgroundColor,
|
||||
this.scrolledUnderBackgroundColor,
|
||||
this.foregroundColor,
|
||||
@Deprecated(
|
||||
'This property is no longer used, please use systemOverlayStyle instead. '
|
||||
'This feature was deprecated after v2.4.0-0.0.pre.',
|
||||
)
|
||||
this.brightness,
|
||||
this.iconTheme,
|
||||
this.actionsIconTheme,
|
||||
@Deprecated(
|
||||
'This property is no longer used, please use toolbarTextStyle and titleTextStyle instead. '
|
||||
'This feature was deprecated after v2.4.0-0.0.pre.',
|
||||
)
|
||||
this.textTheme,
|
||||
this.primary = true,
|
||||
this.centerTitle,
|
||||
this.excludeHeaderSemantics = false,
|
||||
this.titleSpacing,
|
||||
this.collapsedHeight,
|
||||
this.expandedHeight,
|
||||
this.floating = false,
|
||||
this.pinned = false,
|
||||
this.snap = false,
|
||||
this.stretch = false,
|
||||
this.stretchTriggerOffset = 100.0,
|
||||
this.onStretchTrigger,
|
||||
this.shape,
|
||||
this.toolbarHeight = kToolbarHeight,
|
||||
this.leadingWidth,
|
||||
@Deprecated(
|
||||
'This property is obsolete and is false by default. '
|
||||
'This feature was deprecated after v2.4.0-0.0.pre.',
|
||||
)
|
||||
this.backwardsCompatibility,
|
||||
this.toolbarTextStyle,
|
||||
this.titleTextStyle,
|
||||
this.systemOverlayStyle,
|
||||
}) : assert(automaticallyImplyLeading != null),
|
||||
assert(forceElevated != null),
|
||||
assert(primary != null),
|
||||
assert(floating != null),
|
||||
assert(pinned != null),
|
||||
assert(snap != null),
|
||||
assert(stretch != null),
|
||||
assert(toolbarHeight != null),
|
||||
assert(floating || !snap,
|
||||
'The "snap" argument only makes sense for floating app bars.'),
|
||||
assert(stretchTriggerOffset > 0.0),
|
||||
assert(collapsedHeight == null || collapsedHeight >= toolbarHeight,
|
||||
'The "collapsedHeight" argument has to be larger than or equal to [toolbarHeight].'),
|
||||
super(key: key);
|
||||
|
||||
/// {@macro flutter.material.appbar.leading}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final Widget? leading;
|
||||
|
||||
/// {@macro flutter.material.appbar.automaticallyImplyLeading}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final bool automaticallyImplyLeading;
|
||||
|
||||
/// {@macro flutter.material.appbar.title}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final Widget? title;
|
||||
|
||||
/// {@macro flutter.material.appbar.actions}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final List<Widget>? actions;
|
||||
|
||||
/// {@macro flutter.material.appbar.flexibleSpace}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final Widget? flexibleSpace;
|
||||
|
||||
/// {@macro flutter.material.appbar.bottom}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final PreferredSizeWidget? bottom;
|
||||
|
||||
/// {@macro flutter.material.appbar.elevation}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final double? elevation;
|
||||
|
||||
/// {@macro flutter.material.appbar.shadowColor}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final Color? shadowColor;
|
||||
|
||||
/// {@macro flutter.material.appbar.surfaceTintColor}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final Color? surfaceTintColor;
|
||||
|
||||
/// Whether to show the shadow appropriate for the [elevation] even if the
|
||||
/// content is not scrolled under the [AppBar].
|
||||
///
|
||||
/// Defaults to false, meaning that the [elevation] is only applied when the
|
||||
/// [AppBar] is being displayed over content that is scrolled under it.
|
||||
///
|
||||
/// When set to true, the [elevation] is applied regardless.
|
||||
///
|
||||
/// Ignored when [elevation] is zero.
|
||||
final bool forceElevated;
|
||||
|
||||
/// {@macro flutter.material.appbar.backgroundColor}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final Color? backgroundColor;
|
||||
|
||||
final Color? scrolledUnderBackgroundColor;
|
||||
|
||||
/// {@macro flutter.material.appbar.foregroundColor}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final Color? foregroundColor;
|
||||
|
||||
/// {@macro flutter.material.appbar.brightness}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
@Deprecated(
|
||||
'This property is no longer used, please use systemOverlayStyle instead. '
|
||||
'This feature was deprecated after v2.4.0-0.0.pre.',
|
||||
)
|
||||
final Brightness? brightness;
|
||||
|
||||
/// {@macro flutter.material.appbar.iconTheme}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final IconThemeData? iconTheme;
|
||||
|
||||
/// {@macro flutter.material.appbar.actionsIconTheme}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final IconThemeData? actionsIconTheme;
|
||||
|
||||
/// {@macro flutter.material.appbar.textTheme}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
@Deprecated(
|
||||
'This property is no longer used, please use toolbarTextStyle and titleTextStyle instead. '
|
||||
'This feature was deprecated after v2.4.0-0.0.pre.',
|
||||
)
|
||||
final TextTheme? textTheme;
|
||||
|
||||
/// {@macro flutter.material.appbar.primary}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final bool primary;
|
||||
|
||||
/// {@macro flutter.material.appbar.centerTitle}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final bool? centerTitle;
|
||||
|
||||
/// {@macro flutter.material.appbar.excludeHeaderSemantics}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final bool excludeHeaderSemantics;
|
||||
|
||||
/// {@macro flutter.material.appbar.titleSpacing}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final double? titleSpacing;
|
||||
|
||||
/// Defines the height of the app bar when it is collapsed.
|
||||
///
|
||||
/// By default, the collapsed height is [toolbarHeight]. If [bottom] widget is
|
||||
/// specified, then its height from [PreferredSizeWidget.preferredSize] is
|
||||
/// added to the height. If [primary] is true, then the [MediaQuery] top
|
||||
/// padding, [EdgeInsets.top] of [MediaQueryData.padding], is added as well.
|
||||
///
|
||||
/// If [pinned] and [floating] are true, with [bottom] set, the default
|
||||
/// collapsed height is only the height of [PreferredSizeWidget.preferredSize]
|
||||
/// with the [MediaQuery] top padding.
|
||||
final double? collapsedHeight;
|
||||
|
||||
/// The size of the app bar when it is fully expanded.
|
||||
///
|
||||
/// By default, the total height of the toolbar and the bottom widget (if
|
||||
/// any). If a [flexibleSpace] widget is specified this height should be big
|
||||
/// enough to accommodate whatever that widget contains.
|
||||
///
|
||||
/// This does not include the status bar height (which will be automatically
|
||||
/// included if [primary] is true).
|
||||
final double? expandedHeight;
|
||||
|
||||
/// Whether the app bar should become visible as soon as the user scrolls
|
||||
/// towards the app bar.
|
||||
///
|
||||
/// Otherwise, the user will need to scroll near the top of the scroll view to
|
||||
/// reveal the app bar.
|
||||
///
|
||||
/// If [snap] is true then a scroll that exposes the app bar will trigger an
|
||||
/// animation that slides the entire app bar into view. Similarly if a scroll
|
||||
/// dismisses the app bar, the animation will slide it completely out of view.
|
||||
///
|
||||
/// ## Animated Examples
|
||||
///
|
||||
/// The following animations show how the app bar changes its scrolling
|
||||
/// behavior based on the value of this property.
|
||||
///
|
||||
/// * App bar with [floating] set to false:
|
||||
/// {@animation 476 400 https://flutter.github.io/assets-for-api-docs/assets/material/app_bar.mp4}
|
||||
/// * App bar with [floating] set to true:
|
||||
/// {@animation 476 400 https://flutter.github.io/assets-for-api-docs/assets/material/app_bar_floating.mp4}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SliverAppBar] for more animated examples of how this property changes the
|
||||
/// behavior of the app bar in combination with [pinned] and [snap].
|
||||
final bool floating;
|
||||
|
||||
/// Whether the app bar should remain visible at the start of the scroll view.
|
||||
///
|
||||
/// The app bar can still expand and contract as the user scrolls, but it will
|
||||
/// remain visible rather than being scrolled out of view.
|
||||
///
|
||||
/// ## Animated Examples
|
||||
///
|
||||
/// The following animations show how the app bar changes its scrolling
|
||||
/// behavior based on the value of this property.
|
||||
///
|
||||
/// * App bar with [pinned] set to false:
|
||||
/// {@animation 476 400 https://flutter.github.io/assets-for-api-docs/assets/material/app_bar.mp4}
|
||||
/// * App bar with [pinned] set to true:
|
||||
/// {@animation 476 400 https://flutter.github.io/assets-for-api-docs/assets/material/app_bar_pinned.mp4}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SliverAppBar] for more animated examples of how this property changes the
|
||||
/// behavior of the app bar in combination with [floating].
|
||||
final bool pinned;
|
||||
|
||||
/// {@macro flutter.material.appbar.shape}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final ShapeBorder? shape;
|
||||
|
||||
/// If [snap] and [floating] are true then the floating app bar will "snap"
|
||||
/// into view.
|
||||
///
|
||||
/// If [snap] is true then a scroll that exposes the floating app bar will
|
||||
/// trigger an animation that slides the entire app bar into view. Similarly
|
||||
/// if a scroll dismisses the app bar, the animation will slide the app bar
|
||||
/// completely out of view. Additionally, setting [snap] to true will fully
|
||||
/// expand the floating app bar when the framework tries to reveal the
|
||||
/// contents of the app bar by calling [RenderObject.showOnScreen]. For
|
||||
/// example, when a [TextField] in the floating app bar gains focus, if [snap]
|
||||
/// is true, the framework will always fully expand the floating app bar, in
|
||||
/// order to reveal the focused [TextField].
|
||||
///
|
||||
/// Snapping only applies when the app bar is floating, not when the app bar
|
||||
/// appears at the top of its scroll view.
|
||||
///
|
||||
/// ## Animated Examples
|
||||
///
|
||||
/// The following animations show how the app bar changes its scrolling
|
||||
/// behavior based on the value of this property.
|
||||
///
|
||||
/// * App bar with [snap] set to false:
|
||||
/// {@animation 476 400 https://flutter.github.io/assets-for-api-docs/assets/material/app_bar_floating.mp4}
|
||||
/// * App bar with [snap] set to true:
|
||||
/// {@animation 476 400 https://flutter.github.io/assets-for-api-docs/assets/material/app_bar_floating_snap.mp4}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SliverAppBar] for more animated examples of how this property changes the
|
||||
/// behavior of the app bar in combination with [pinned] and [floating].
|
||||
final bool snap;
|
||||
|
||||
/// Whether the app bar should stretch to fill the over-scroll area.
|
||||
///
|
||||
/// The app bar can still expand and contract as the user scrolls, but it will
|
||||
/// also stretch when the user over-scrolls.
|
||||
final bool stretch;
|
||||
|
||||
/// The offset of overscroll required to activate [onStretchTrigger].
|
||||
///
|
||||
/// This defaults to 100.0.
|
||||
final double stretchTriggerOffset;
|
||||
|
||||
/// The callback function to be executed when a user over-scrolls to the
|
||||
/// offset specified by [stretchTriggerOffset].
|
||||
final AsyncCallback? onStretchTrigger;
|
||||
|
||||
/// {@macro flutter.material.appbar.toolbarHeight}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final double toolbarHeight;
|
||||
|
||||
/// {@macro flutter.material.appbar.leadingWidth}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final double? leadingWidth;
|
||||
|
||||
/// {@macro flutter.material.appbar.backwardsCompatibility}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
@Deprecated(
|
||||
'This property is obsolete and is false by default. '
|
||||
'This feature was deprecated after v2.4.0-0.0.pre.',
|
||||
)
|
||||
final bool? backwardsCompatibility;
|
||||
|
||||
/// {@macro flutter.material.appbar.toolbarTextStyle}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final TextStyle? toolbarTextStyle;
|
||||
|
||||
/// {@macro flutter.material.appbar.titleTextStyle}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final TextStyle? titleTextStyle;
|
||||
|
||||
/// {@macro flutter.material.appbar.systemOverlayStyle}
|
||||
///
|
||||
/// This property is used to configure an [AppBar].
|
||||
final SystemUiOverlayStyle? systemOverlayStyle;
|
||||
|
||||
@override
|
||||
State<TranslucentSliverAppBar> createState() => _SliverAppBarState();
|
||||
}
|
||||
|
||||
class _SliverAppBarState extends State<TranslucentSliverAppBar>
|
||||
with TickerProviderStateMixin {
|
||||
FloatingHeaderSnapConfiguration? _snapConfiguration;
|
||||
OverScrollHeaderStretchConfiguration? _stretchConfiguration;
|
||||
PersistentHeaderShowOnScreenConfiguration? _showOnScreenConfiguration;
|
||||
|
||||
void _updateSnapConfiguration() {
|
||||
if (widget.snap && widget.floating) {
|
||||
_snapConfiguration = FloatingHeaderSnapConfiguration(
|
||||
curve: Curves.easeOut,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
);
|
||||
} else {
|
||||
_snapConfiguration = null;
|
||||
}
|
||||
|
||||
_showOnScreenConfiguration = widget.floating & widget.snap
|
||||
? const PersistentHeaderShowOnScreenConfiguration(
|
||||
minShowOnScreenExtent: double.infinity)
|
||||
: null;
|
||||
}
|
||||
|
||||
void _updateStretchConfiguration() {
|
||||
if (widget.stretch) {
|
||||
_stretchConfiguration = OverScrollHeaderStretchConfiguration(
|
||||
stretchTriggerOffset: widget.stretchTriggerOffset,
|
||||
onStretchTrigger: widget.onStretchTrigger,
|
||||
);
|
||||
} else {
|
||||
_stretchConfiguration = null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_updateSnapConfiguration();
|
||||
_updateStretchConfiguration();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(TranslucentSliverAppBar oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.snap != oldWidget.snap || widget.floating != oldWidget.floating)
|
||||
_updateSnapConfiguration();
|
||||
if (widget.stretch != oldWidget.stretch) _updateStretchConfiguration();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(!widget.primary || debugCheckHasMediaQuery(context));
|
||||
final double bottomHeight = widget.bottom?.preferredSize.height ?? 0.0;
|
||||
final double topPadding =
|
||||
widget.primary ? MediaQuery.of(context).padding.top : 0.0;
|
||||
final double collapsedHeight =
|
||||
(widget.pinned && widget.floating && widget.bottom != null)
|
||||
? (widget.collapsedHeight ?? 0.0) + bottomHeight + topPadding
|
||||
: (widget.collapsedHeight ?? widget.toolbarHeight) +
|
||||
bottomHeight +
|
||||
topPadding;
|
||||
|
||||
return MediaQuery.removePadding(
|
||||
context: context,
|
||||
removeBottom: true,
|
||||
child: SliverPersistentHeader(
|
||||
floating: widget.floating,
|
||||
pinned: widget.pinned,
|
||||
delegate: _SliverAppBarDelegate(
|
||||
vsync: this,
|
||||
leading: widget.leading,
|
||||
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
||||
title: widget.title,
|
||||
actions: widget.actions,
|
||||
flexibleSpace: widget.flexibleSpace,
|
||||
bottom: widget.bottom,
|
||||
elevation: widget.elevation,
|
||||
shadowColor: widget.shadowColor,
|
||||
surfaceTintColor: widget.surfaceTintColor,
|
||||
forceElevated: widget.forceElevated,
|
||||
backgroundColor: widget.backgroundColor,
|
||||
scrolledUnderBackgroundColor: widget.scrolledUnderBackgroundColor,
|
||||
foregroundColor: widget.foregroundColor,
|
||||
brightness: widget.brightness,
|
||||
iconTheme: widget.iconTheme,
|
||||
actionsIconTheme: widget.actionsIconTheme,
|
||||
textTheme: widget.textTheme,
|
||||
primary: widget.primary,
|
||||
centerTitle: widget.centerTitle,
|
||||
excludeHeaderSemantics: widget.excludeHeaderSemantics,
|
||||
titleSpacing: widget.titleSpacing,
|
||||
expandedHeight: widget.expandedHeight,
|
||||
collapsedHeight: collapsedHeight,
|
||||
topPadding: topPadding,
|
||||
floating: widget.floating,
|
||||
pinned: widget.pinned,
|
||||
shape: widget.shape,
|
||||
snapConfiguration: _snapConfiguration,
|
||||
stretchConfiguration: _stretchConfiguration,
|
||||
showOnScreenConfiguration: _showOnScreenConfiguration,
|
||||
toolbarHeight: widget.toolbarHeight,
|
||||
leadingWidth: widget.leadingWidth,
|
||||
backwardsCompatibility: widget.backwardsCompatibility,
|
||||
toolbarTextStyle: widget.toolbarTextStyle,
|
||||
titleTextStyle: widget.titleTextStyle,
|
||||
systemOverlayStyle: widget.systemOverlayStyle,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
||||
_SliverAppBarDelegate({
|
||||
required this.leading,
|
||||
required this.automaticallyImplyLeading,
|
||||
required this.title,
|
||||
required this.actions,
|
||||
required this.flexibleSpace,
|
||||
required this.bottom,
|
||||
required this.elevation,
|
||||
required this.shadowColor,
|
||||
required this.surfaceTintColor,
|
||||
required this.forceElevated,
|
||||
required this.backgroundColor,
|
||||
required this.scrolledUnderBackgroundColor,
|
||||
required this.foregroundColor,
|
||||
required this.brightness,
|
||||
required this.iconTheme,
|
||||
required this.actionsIconTheme,
|
||||
required this.textTheme,
|
||||
required this.primary,
|
||||
required this.centerTitle,
|
||||
required this.excludeHeaderSemantics,
|
||||
required this.titleSpacing,
|
||||
required this.expandedHeight,
|
||||
required this.collapsedHeight,
|
||||
required this.topPadding,
|
||||
required this.floating,
|
||||
required this.pinned,
|
||||
required this.vsync,
|
||||
required this.snapConfiguration,
|
||||
required this.stretchConfiguration,
|
||||
required this.showOnScreenConfiguration,
|
||||
required this.shape,
|
||||
required this.toolbarHeight,
|
||||
required this.leadingWidth,
|
||||
required this.backwardsCompatibility,
|
||||
required this.toolbarTextStyle,
|
||||
required this.titleTextStyle,
|
||||
required this.systemOverlayStyle,
|
||||
}) : assert(primary || topPadding == 0.0),
|
||||
assert(
|
||||
!floating ||
|
||||
(snapConfiguration == null &&
|
||||
showOnScreenConfiguration == null) ||
|
||||
vsync != null,
|
||||
'vsync cannot be null when snapConfiguration or showOnScreenConfiguration is not null, and floating is true',
|
||||
),
|
||||
_bottomHeight = bottom?.preferredSize.height ?? 0.0;
|
||||
|
||||
final Widget? leading;
|
||||
final bool automaticallyImplyLeading;
|
||||
final Widget? title;
|
||||
final List<Widget>? actions;
|
||||
final Widget? flexibleSpace;
|
||||
final PreferredSizeWidget? bottom;
|
||||
final double? elevation;
|
||||
final Color? shadowColor;
|
||||
final Color? surfaceTintColor;
|
||||
final bool forceElevated;
|
||||
final Color? backgroundColor;
|
||||
final Color? scrolledUnderBackgroundColor;
|
||||
final Color? foregroundColor;
|
||||
final Brightness? brightness;
|
||||
final IconThemeData? iconTheme;
|
||||
final IconThemeData? actionsIconTheme;
|
||||
final TextTheme? textTheme;
|
||||
final bool primary;
|
||||
final bool? centerTitle;
|
||||
final bool excludeHeaderSemantics;
|
||||
final double? titleSpacing;
|
||||
final double? expandedHeight;
|
||||
final double collapsedHeight;
|
||||
final double topPadding;
|
||||
final bool floating;
|
||||
final bool pinned;
|
||||
final ShapeBorder? shape;
|
||||
final double? toolbarHeight;
|
||||
final double? leadingWidth;
|
||||
final bool? backwardsCompatibility;
|
||||
final TextStyle? toolbarTextStyle;
|
||||
final TextStyle? titleTextStyle;
|
||||
final SystemUiOverlayStyle? systemOverlayStyle;
|
||||
final double _bottomHeight;
|
||||
|
||||
@override
|
||||
double get minExtent => collapsedHeight;
|
||||
|
||||
@override
|
||||
double get maxExtent => math.max(
|
||||
topPadding +
|
||||
(expandedHeight ?? (toolbarHeight ?? kToolbarHeight) + _bottomHeight),
|
||||
minExtent);
|
||||
|
||||
@override
|
||||
final TickerProvider vsync;
|
||||
|
||||
@override
|
||||
final FloatingHeaderSnapConfiguration? snapConfiguration;
|
||||
|
||||
@override
|
||||
final OverScrollHeaderStretchConfiguration? stretchConfiguration;
|
||||
|
||||
@override
|
||||
final PersistentHeaderShowOnScreenConfiguration? showOnScreenConfiguration;
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||
final double visibleMainHeight = maxExtent - shrinkOffset - topPadding;
|
||||
final double extraToolbarHeight = math.max(
|
||||
minExtent -
|
||||
_bottomHeight -
|
||||
topPadding -
|
||||
(toolbarHeight ?? kToolbarHeight),
|
||||
0.0);
|
||||
final double visibleToolbarHeight =
|
||||
visibleMainHeight - _bottomHeight - extraToolbarHeight;
|
||||
|
||||
final bool isScrolledUnder =
|
||||
overlapsContent || (pinned && shrinkOffset > maxExtent - minExtent);
|
||||
final bool isPinnedWithOpacityFade =
|
||||
pinned && floating && bottom != null && extraToolbarHeight == 0.0;
|
||||
final double toolbarOpacity = !pinned || isPinnedWithOpacityFade
|
||||
? (visibleToolbarHeight / (toolbarHeight ?? kToolbarHeight))
|
||||
.clamp(0.0, 1.0)
|
||||
: 1.0;
|
||||
|
||||
final Widget appBar = FlexibleSpaceBar.createSettings(
|
||||
minExtent: minExtent,
|
||||
maxExtent: maxExtent,
|
||||
currentExtent: math.max(minExtent, maxExtent - shrinkOffset),
|
||||
toolbarOpacity: toolbarOpacity,
|
||||
isScrolledUnder: isScrolledUnder,
|
||||
child: Stack(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: math.max(minExtent, maxExtent - shrinkOffset),
|
||||
child: ClipRect(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 4, sigmaY: 4),
|
||||
child: const ColoredBox(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
AppBar(
|
||||
leading: leading,
|
||||
automaticallyImplyLeading: automaticallyImplyLeading,
|
||||
title: title,
|
||||
actions: actions,
|
||||
flexibleSpace: (title == null &&
|
||||
flexibleSpace != null &&
|
||||
!excludeHeaderSemantics)
|
||||
? Semantics(
|
||||
header: true,
|
||||
child: flexibleSpace,
|
||||
)
|
||||
: flexibleSpace,
|
||||
bottom: bottom,
|
||||
elevation: forceElevated || isScrolledUnder ? elevation : 0.0,
|
||||
scrolledUnderElevation: 0,
|
||||
shadowColor: shadowColor,
|
||||
surfaceTintColor: surfaceTintColor,
|
||||
backgroundColor: isScrolledUnder
|
||||
? scrolledUnderBackgroundColor
|
||||
: backgroundColor,
|
||||
foregroundColor: foregroundColor,
|
||||
brightness: brightness,
|
||||
iconTheme: iconTheme,
|
||||
actionsIconTheme: actionsIconTheme,
|
||||
textTheme: textTheme,
|
||||
primary: primary,
|
||||
centerTitle: centerTitle,
|
||||
excludeHeaderSemantics: excludeHeaderSemantics,
|
||||
titleSpacing: titleSpacing,
|
||||
shape: shape,
|
||||
toolbarOpacity: toolbarOpacity,
|
||||
bottomOpacity: pinned
|
||||
? 1.0
|
||||
: ((visibleMainHeight / _bottomHeight).clamp(0.0, 1.0)),
|
||||
toolbarHeight: toolbarHeight,
|
||||
leadingWidth: leadingWidth,
|
||||
backwardsCompatibility: backwardsCompatibility,
|
||||
toolbarTextStyle: toolbarTextStyle,
|
||||
titleTextStyle: titleTextStyle,
|
||||
systemOverlayStyle: systemOverlayStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
return appBar;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRebuild(covariant _SliverAppBarDelegate oldDelegate) {
|
||||
return leading != oldDelegate.leading ||
|
||||
automaticallyImplyLeading != oldDelegate.automaticallyImplyLeading ||
|
||||
title != oldDelegate.title ||
|
||||
actions != oldDelegate.actions ||
|
||||
flexibleSpace != oldDelegate.flexibleSpace ||
|
||||
bottom != oldDelegate.bottom ||
|
||||
_bottomHeight != oldDelegate._bottomHeight ||
|
||||
elevation != oldDelegate.elevation ||
|
||||
shadowColor != oldDelegate.shadowColor ||
|
||||
backgroundColor != oldDelegate.backgroundColor ||
|
||||
scrolledUnderBackgroundColor !=
|
||||
oldDelegate.scrolledUnderBackgroundColor ||
|
||||
foregroundColor != oldDelegate.foregroundColor ||
|
||||
brightness != oldDelegate.brightness ||
|
||||
iconTheme != oldDelegate.iconTheme ||
|
||||
actionsIconTheme != oldDelegate.actionsIconTheme ||
|
||||
textTheme != oldDelegate.textTheme ||
|
||||
primary != oldDelegate.primary ||
|
||||
centerTitle != oldDelegate.centerTitle ||
|
||||
titleSpacing != oldDelegate.titleSpacing ||
|
||||
expandedHeight != oldDelegate.expandedHeight ||
|
||||
topPadding != oldDelegate.topPadding ||
|
||||
pinned != oldDelegate.pinned ||
|
||||
floating != oldDelegate.floating ||
|
||||
vsync != oldDelegate.vsync ||
|
||||
snapConfiguration != oldDelegate.snapConfiguration ||
|
||||
stretchConfiguration != oldDelegate.stretchConfiguration ||
|
||||
showOnScreenConfiguration != oldDelegate.showOnScreenConfiguration ||
|
||||
forceElevated != oldDelegate.forceElevated ||
|
||||
toolbarHeight != oldDelegate.toolbarHeight ||
|
||||
leadingWidth != oldDelegate.leadingWidth ||
|
||||
backwardsCompatibility != oldDelegate.backwardsCompatibility ||
|
||||
toolbarTextStyle != oldDelegate.toolbarTextStyle ||
|
||||
titleTextStyle != oldDelegate.titleTextStyle ||
|
||||
systemOverlayStyle != oldDelegate.systemOverlayStyle;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '${describeIdentity(this)}(topPadding: ${topPadding.toStringAsFixed(1)}, bottomHeight: ${_bottomHeight.toStringAsFixed(1)}, ...)';
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue