mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
182 lines
5.6 KiB
Dart
182 lines
5.6 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
|
|
/// https://github.com/flutter/flutter/issues/18345#issuecomment-1627644396
|
|
class DynamicSliverAppBar extends StatefulWidget {
|
|
const DynamicSliverAppBar({
|
|
this.flexibleSpace,
|
|
super.key,
|
|
this.leading,
|
|
this.automaticallyImplyLeading = true,
|
|
this.title,
|
|
this.actions,
|
|
this.bottom,
|
|
this.elevation,
|
|
this.scrolledUnderElevation,
|
|
this.shadowColor,
|
|
this.surfaceTintColor,
|
|
this.forceElevated = false,
|
|
this.backgroundColor,
|
|
this.backgroundGradient,
|
|
this.foregroundColor,
|
|
this.iconTheme,
|
|
this.actionsIconTheme,
|
|
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 + 20,
|
|
this.leadingWidth,
|
|
this.toolbarTextStyle,
|
|
this.titleTextStyle,
|
|
this.systemOverlayStyle,
|
|
this.forceMaterialTransparency = false,
|
|
this.clipBehavior,
|
|
this.appBarClipper,
|
|
});
|
|
|
|
final Widget? flexibleSpace;
|
|
final Widget? leading;
|
|
final bool automaticallyImplyLeading;
|
|
final Widget? title;
|
|
final List<Widget>? actions;
|
|
final PreferredSizeWidget? bottom;
|
|
final double? elevation;
|
|
final double? scrolledUnderElevation;
|
|
final Color? shadowColor;
|
|
final Color? surfaceTintColor;
|
|
final bool forceElevated;
|
|
final Color? backgroundColor;
|
|
|
|
/// If backgroundGradient is non null, backgroundColor will be ignored
|
|
final LinearGradient? backgroundGradient;
|
|
final Color? foregroundColor;
|
|
final IconThemeData? iconTheme;
|
|
final IconThemeData? actionsIconTheme;
|
|
final bool primary;
|
|
final bool? centerTitle;
|
|
final bool excludeHeaderSemantics;
|
|
final double? titleSpacing;
|
|
final double? expandedHeight;
|
|
final double? collapsedHeight;
|
|
final bool floating;
|
|
final bool pinned;
|
|
final ShapeBorder? shape;
|
|
final double toolbarHeight;
|
|
final double? leadingWidth;
|
|
final TextStyle? toolbarTextStyle;
|
|
final TextStyle? titleTextStyle;
|
|
final SystemUiOverlayStyle? systemOverlayStyle;
|
|
final bool forceMaterialTransparency;
|
|
final Clip? clipBehavior;
|
|
final bool snap;
|
|
final bool stretch;
|
|
final double stretchTriggerOffset;
|
|
final AsyncCallback? onStretchTrigger;
|
|
final CustomClipper<Path>? appBarClipper;
|
|
|
|
@override
|
|
State<DynamicSliverAppBar> createState() => _DynamicSliverAppBarState();
|
|
}
|
|
|
|
class _DynamicSliverAppBarState extends State<DynamicSliverAppBar> {
|
|
final GlobalKey _childKey = GlobalKey();
|
|
|
|
// As long as the height is 0 instead of the sliver app bar a sliver to box adapter will be used
|
|
// to calculate dynamically the size for the sliver app bar
|
|
double _height = 0;
|
|
Orientation? _orientation;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_updateHeight();
|
|
}
|
|
|
|
@override
|
|
void didUpdateWidget(covariant DynamicSliverAppBar oldWidget) {
|
|
super.didUpdateWidget(oldWidget);
|
|
|
|
_updateHeight();
|
|
}
|
|
|
|
void _updateHeight() {
|
|
// Gets the new height and updates the sliver app bar. Needs to be called after the last frame has been rebuild
|
|
// otherwise this will throw an error
|
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
|
if (_childKey.currentContext == null) return;
|
|
setState(() {
|
|
_height = (_childKey.currentContext!.findRenderObject()! as RenderBox)
|
|
.size
|
|
.height;
|
|
});
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
//Needed to lay out the flexibleSpace the first time, so we can calculate its intrinsic height
|
|
Orientation orientation = MediaQuery.orientationOf(context);
|
|
if (_orientation != orientation) {
|
|
_orientation = orientation;
|
|
_height = 0;
|
|
}
|
|
if (_height == 0) {
|
|
return SliverToBoxAdapter(
|
|
child: Container(
|
|
key: _childKey,
|
|
child: widget.flexibleSpace ?? SizedBox(height: kToolbarHeight),
|
|
),
|
|
);
|
|
}
|
|
|
|
return SliverAppBar(
|
|
leading: widget.leading,
|
|
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
|
title: widget.title,
|
|
actions: widget.actions,
|
|
bottom: widget.bottom,
|
|
elevation: widget.elevation,
|
|
scrolledUnderElevation: widget.scrolledUnderElevation,
|
|
shadowColor: widget.shadowColor,
|
|
surfaceTintColor: widget.surfaceTintColor,
|
|
forceElevated: widget.forceElevated,
|
|
backgroundColor: widget.backgroundColor,
|
|
foregroundColor: widget.foregroundColor,
|
|
iconTheme: widget.iconTheme,
|
|
actionsIconTheme: widget.actionsIconTheme,
|
|
primary: widget.primary,
|
|
centerTitle: widget.centerTitle,
|
|
excludeHeaderSemantics: widget.excludeHeaderSemantics,
|
|
titleSpacing: widget.titleSpacing,
|
|
collapsedHeight: widget.collapsedHeight,
|
|
floating: widget.floating,
|
|
pinned: widget.pinned,
|
|
snap: widget.snap,
|
|
stretch: widget.stretch,
|
|
stretchTriggerOffset: widget.stretchTriggerOffset,
|
|
onStretchTrigger: widget.onStretchTrigger,
|
|
shape: widget.shape,
|
|
toolbarHeight: widget.toolbarHeight,
|
|
expandedHeight: _height,
|
|
leadingWidth: widget.leadingWidth,
|
|
toolbarTextStyle: widget.toolbarTextStyle,
|
|
titleTextStyle: widget.titleTextStyle,
|
|
systemOverlayStyle: widget.systemOverlayStyle,
|
|
forceMaterialTransparency: widget.forceMaterialTransparency,
|
|
clipBehavior: widget.clipBehavior,
|
|
flexibleSpace: FlexibleSpaceBar(background: widget.flexibleSpace),
|
|
);
|
|
}
|
|
}
|