Files
mobile/patchs/cupertino_transp_appbar.patch
2024-05-07 16:10:52 +02:00

206 lines
8.5 KiB
Diff

diff --git a/packages/flutter/lib/src/cupertino/nav_bar.dart b/packages/flutter/lib/src/cupertino/nav_bar.dart
index 1495f55d2d..a3ef08bdb6 100644
--- a/packages/flutter/lib/src/cupertino/nav_bar.dart
+++ b/packages/flutter/lib/src/cupertino/nav_bar.dart
@@ -31,6 +31,10 @@ const double _kNavBarLargeTitleHeightExtension = 52.0;
/// from the normal navigation bar to a big title below the navigation bar.
const double _kNavBarShowLargeTitleThreshold = 10.0;
+/// Number of logical pixels scrolled during which the navigation bar's background
+/// fades in or out.
+const _kNavBarScrollUnderAnimationExtent = 10.0;
+
const double _kNavBarEdgePadding = 16.0;
const double _kNavBarBottomPadding = 8.0;
@@ -432,17 +436,81 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer
class _CupertinoNavigationBarState extends State<CupertinoNavigationBar> {
late _NavigationBarStaticComponentsKeys keys;
+ ScrollNotificationObserverState? _scrollNotificationObserver;
+ double _scrollAnimationValue = 0.0;
+
+ @override
+ void didChangeDependencies() {
+ super.didChangeDependencies();
+ _scrollNotificationObserver?.removeListener(_handleScrollNotification);
+ _scrollNotificationObserver = ScrollNotificationObserver.maybeOf(context);
+ _scrollNotificationObserver?.addListener(_handleScrollNotification);
+ }
+
+ @override
+ void dispose() {
+ if (_scrollNotificationObserver != null) {
+ _scrollNotificationObserver!.removeListener(_handleScrollNotification);
+ _scrollNotificationObserver = null;
+ }
+ super.dispose();
+ }
+
@override
void initState() {
super.initState();
keys = _NavigationBarStaticComponentsKeys();
}
+ void _handleScrollNotification(ScrollNotification notification) {
+ if (notification is ScrollUpdateNotification && notification.depth == 0) {
+ final ScrollMetrics metrics = notification.metrics;
+ final oldScrollAnimationValue = _scrollAnimationValue;
+ double scrollExtent = 0.0;
+ switch (metrics.axisDirection) {
+ case AxisDirection.up:
+ // Scroll view is reversed
+ scrollExtent = metrics.extentAfter;
+ case AxisDirection.down:
+ scrollExtent = metrics.extentBefore;
+ case AxisDirection.right:
+ case AxisDirection.left:
+ // Scrolled under is only supported in the vertical axis, and should
+ // not be altered based on horizontal notifications of the same
+ // predicate since it could be a 2D scroller.
+ break;
+ }
+
+ if (scrollExtent >= 0 && scrollExtent < _kNavBarScrollUnderAnimationExtent) {
+ setState(() {
+ _scrollAnimationValue = clampDouble(scrollExtent / _kNavBarScrollUnderAnimationExtent, 0, 1);
+ });
+ } else if (scrollExtent > _kNavBarScrollUnderAnimationExtent && oldScrollAnimationValue != 1.0) {
+ setState(() {
+ _scrollAnimationValue = 1.0;
+ });
+ } else if (scrollExtent <= 0 && oldScrollAnimationValue != 0.0) {
+ setState(() {
+ _scrollAnimationValue = 0.0;
+ });
+ }
+ }
+ }
+
@override
Widget build(BuildContext context) {
final Color backgroundColor =
CupertinoDynamicColor.maybeResolve(widget.backgroundColor, context) ?? CupertinoTheme.of(context).barBackgroundColor;
+ final Border? effectiveBorder = Border.lerp(
+ const Border(bottom: BorderSide(width: 0.0, color: Color(0x00000000))),
+ widget.border,
+ _scrollAnimationValue,
+ );
+
+ final initialBackgroundColor = CupertinoTheme.of(context).scaffoldBackgroundColor;
+ final Color effectiveBackgroundColor = Color.lerp(initialBackgroundColor, backgroundColor, _scrollAnimationValue)!;
+
final _NavigationBarStaticComponents components = _NavigationBarStaticComponents(
keys: keys,
route: ModalRoute.of(context),
@@ -458,8 +526,8 @@ class _CupertinoNavigationBarState extends State<CupertinoNavigationBar> {
);
final Widget navBar = _wrapWithBackground(
- border: widget.border,
- backgroundColor: backgroundColor,
+ border: effectiveBorder,
+ backgroundColor: effectiveBackgroundColor,
brightness: widget.brightness,
child: DefaultTextStyle(
style: CupertinoTheme.of(context).textTheme.textStyle,
@@ -488,11 +556,11 @@ class _CupertinoNavigationBarState extends State<CupertinoNavigationBar> {
transitionOnUserGestures: true,
child: _TransitionableNavigationBar(
componentsKeys: keys,
- backgroundColor: backgroundColor,
+ backgroundColor: effectiveBackgroundColor,
backButtonTextStyle: CupertinoTheme.of(context).textTheme.navActionTextStyle,
titleTextStyle: CupertinoTheme.of(context).textTheme.navTitleTextStyle,
largeTitleTextStyle: null,
- border: widget.border,
+ border: effectiveBorder,
hasUserMiddle: widget.middle != null,
largeExpanded: false,
child: navBar,
@@ -792,7 +860,13 @@ class _LargeTitleNavigationBarSliverDelegate
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
- final bool showLargeTitle = shrinkOffset < maxExtent - minExtent - _kNavBarShowLargeTitleThreshold;
+ final double largeTitleThreshold = maxExtent - minExtent - _kNavBarShowLargeTitleThreshold;
+ final bool showLargeTitle = shrinkOffset < largeTitleThreshold;
+ final double shrinkAnimationValue = clampDouble(
+ (shrinkOffset - largeTitleThreshold - _kNavBarScrollUnderAnimationExtent) / _kNavBarScrollUnderAnimationExtent,
+ 0,
+ 1,
+ );
final _PersistentNavigationBar persistentNavigationBar =
_PersistentNavigationBar(
@@ -803,9 +877,21 @@ class _LargeTitleNavigationBarSliverDelegate
middleVisible: alwaysShowMiddle ? null : !showLargeTitle,
);
+ final Color effectiveBackgroundColor = Color.lerp(
+ CupertinoTheme.of(context).scaffoldBackgroundColor,
+ CupertinoDynamicColor.resolve(backgroundColor, context),
+ shrinkAnimationValue,
+ )!;
+
+ final Border? effectiveBorder = border == null ? null : Border.lerp(
+ const Border(bottom: BorderSide(width: 0.0, color: Color(0x00000000))),
+ border,
+ shrinkAnimationValue,
+ );
+
final Widget navBar = _wrapWithBackground(
- border: border,
- backgroundColor: CupertinoDynamicColor.resolve(backgroundColor, context),
+ border: effectiveBorder,
+ backgroundColor: effectiveBackgroundColor,
brightness: brightness,
child: DefaultTextStyle(
style: CupertinoTheme.of(context).textTheme.textStyle,
@@ -875,11 +961,11 @@ class _LargeTitleNavigationBarSliverDelegate
// needs to wrap the top level RenderBox rather than a RenderSliver.
child: _TransitionableNavigationBar(
componentsKeys: keys,
- backgroundColor: CupertinoDynamicColor.resolve(backgroundColor, context),
+ backgroundColor: effectiveBackgroundColor,
backButtonTextStyle: CupertinoTheme.of(context).textTheme.navActionTextStyle,
titleTextStyle: CupertinoTheme.of(context).textTheme.navTitleTextStyle,
largeTitleTextStyle: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle,
- border: border,
+ border: effectiveBorder,
hasUserMiddle: userMiddle != null && (alwaysShowMiddle || !showLargeTitle),
largeExpanded: showLargeTitle,
child: navBar,
@@ -1716,6 +1802,7 @@ class _NavigationBarTransition extends StatelessWidget {
AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget? child) {
+
return _wrapWithBackground(
// Don't update the system status bar color mid-flight.
updateSystemUiOverlay: false,
diff --git a/packages/flutter/lib/src/cupertino/page_scaffold.dart b/packages/flutter/lib/src/cupertino/page_scaffold.dart
index 7eec24d908..4bc5fbc87a 100644
--- a/packages/flutter/lib/src/cupertino/page_scaffold.dart
+++ b/packages/flutter/lib/src/cupertino/page_scaffold.dart
@@ -165,7 +165,7 @@ class _CupertinoPageScaffoldState extends State<CupertinoPageScaffold> {
);
}
- return DecoratedBox(
+ final content = DecoratedBox(
decoration: BoxDecoration(
color: CupertinoDynamicColor.maybeResolve(widget.backgroundColor, context)
?? CupertinoTheme.of(context).scaffoldBackgroundColor,
@@ -198,6 +198,8 @@ class _CupertinoPageScaffoldState extends State<CupertinoPageScaffold> {
],
),
);
+
+ return ScrollNotificationObserver(child: content);
}
}