Skip to content

Commit

Permalink
Use the custom top bar in scroll animation
Browse files Browse the repository at this point in the history
  • Loading branch information
ulusoyca committed Oct 8, 2023
1 parent f238fab commit aa99c21
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 57 deletions.
38 changes: 24 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,27 +104,37 @@ the sheet, situated directly above the top bar on the z-axis. It includes
two specific widgets: the leading and the trailing. The leading widget
usually functions as the back button, enabling users to navigate to the
previous page. The trailing widget often serves as the close button, utilized to
close the modal sheet. Together, these widgets provide clear and intuitive
navigational control, differentiating themselves from the top bar by focusing
specifically on directional navigation within the interface.
close the modal sheet. The middle area is reserved and left empty for the
visibility of the top bar title.
</br>
</br>
The navigation bar widgets provide clear and intuitive navigational control,
differentiating themselves from the top bar by focusing specifically on
directional navigation within the interface.

### Top bar and top bar title

The Top Bar sits above the main content layer and below the navigation
bar layer. It aids users in grasping the context by displaying an optional
title. In scenarios where sheets are filled with content requiring scrolling,
the top bar becomes visible as the user scrolls, causing the page title
replaced. At this point, the top bar adopts a 'sticky' position at the top,
guaranteeing consistent visibility. Its design is flexible, with an option
to remain hidden or always visible regardless of the scroll position. The
navigation bar widgets overlay above the top bar, and the top bar title is
symmetrically framed between the leading and trailing navigation bar widgets.
The top bar layer sits above the main content layer and below the navigation
bar layer in z axis. It helps users grasping the context by displaying an
optional title. In scenarios where the sheet is filled with content
requiring scrolling, the top bar becomes visible as the user scrolls, and
replaces the page title. At this point, the top bar adopts a 'sticky'
position at the top, guaranteeing consistent visibility.
</br>
</br>
The Top Bar design is flexible, when `hasTopBarLayer` is set to false, the
top bar and the `topBarTitle` will be hidden. If
The top bar widget has a flexible design. When `hasTopBarLayer` is set to
false, the top bar and the top bar title will not be shown. If
`isTopBarLayerAlwaysVisible` set to true, the top bar will be always visible
regardless of the scroll position.
</br>
</br>
A custom top bar widget can be provided using the `topBar` field. In this
case, the `topBarTitle` field will be ignored, and will not be displayed.
</br>
</br>
The navigation bar widgets overlay above the top bar, and when the default
top bar widget is used in the page, the top bar title is symmetrically
framed between the leading and trailing navigation bar widgets.

### Sticky action bar (SAB)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,70 @@ import 'package:flutter/material.dart';
import 'package:wolt_modal_sheet/src/theme/wolt_modal_sheet_default_theme_data.dart';
import 'package:wolt_modal_sheet/wolt_modal_sheet.dart';

/// Top bar widget used in a [WoltModalSheetPage].
///
/// If [WoltModalSheetPage.topBar] is provided, this widget wraps it with a shadow and elevation
/// as specified by the theme or defaults. In the absence of a [WoltModalSheetPage.topBar], this
/// widget creates a default top bar styled with the appropriate theme settings.
///
/// The widget respects the modal sheet's page settings, such as [WoltModalSheetPage.navBarHeight]
/// and [WoltModalSheetPage.backgroundColor]. It also respects custom theme settings through
/// [WoltModalSheetThemeData] while falling back to [WoltModalSheetDefaultThemeData] for default
/// theming values.
class WoltModalSheetTopBar extends StatelessWidget {
/// The modal sheet page that contains the configuration and content settings.
final WoltModalSheetPage page;

const WoltModalSheetTopBar({required this.page, Key? key}) : super(key: key);
/// Creates a new instance of [WoltModalSheetTopBar].
const WoltModalSheetTopBar({
required this.page,
Key? key,
}) : super(key: key);

@override
Widget build(BuildContext context) {
// Obtain the current theme and modal sheet-specific theme settings.
final theme = Theme.of(context);
final themeData = theme.extension<WoltModalSheetThemeData>();
final defaultThemeData = WoltModalSheetDefaultThemeData(context);

// Determine the top bar's elevation, shadow color, height, background color, and surface tint color.
final elevation = themeData?.topBarElevation ?? defaultThemeData.topBarElevation;
final shadowColor = themeData?.topBarShadowColor ??
(theme.brightness == Brightness.light ? const Color(0xFFE4E4E4) : const Color(0xFF121212));
final topBarHeight = page.navBarHeight ??
themeData?.navBarHeight ??
defaultThemeData.navBarHeight;
final topBarHeight =
page.navBarHeight ?? themeData?.navBarHeight ?? defaultThemeData.navBarHeight;
final backgroundColor =
page.backgroundColor ?? themeData?.backgroundColor ?? defaultThemeData.backgroundColor;
final surfaceTintColor = themeData?.surfaceTintColor ?? defaultThemeData.surfaceTintColor;

return Column(
children: [
Material(
type: MaterialType.canvas,
color: backgroundColor,
surfaceTintColor: surfaceTintColor,
shadowColor: shadowColor,
elevation: elevation,
child: SizedBox(height: topBarHeight - elevation, width: double.infinity),
),
// Check if page.topBar is not null; if it is, create the default Material top bar.
page.topBar != null
? Material(
type: MaterialType.canvas,
color: backgroundColor,
surfaceTintColor: surfaceTintColor,
shadowColor: shadowColor,
elevation: elevation,
child: SizedBox(
height: topBarHeight - elevation,
width: double.infinity,
child: page.topBar,
),
)
: Material(
type: MaterialType.canvas,
color: backgroundColor,
surfaceTintColor: surfaceTintColor,
shadowColor: shadowColor,
elevation: elevation,
child: SizedBox(
height: topBarHeight - elevation,
width: double.infinity,
),
),
SizedBox(height: elevation),
],
);
Expand Down
33 changes: 16 additions & 17 deletions lib/src/content/wolt_modal_sheet_animated_switcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,21 @@ class _WoltModalSheetAnimatedSwitcherState extends State<WoltModalSheetAnimatedS
final topBarTitle = WoltModalSheetTopBarTitle(page: _page, pageTitleKey: _pageTitleKey);
final navBarHeight =
_page.navBarHeight ?? themeData?.navBarHeight ?? defaultThemeData.navBarHeight;

assert(_page.topBarWidget == null || isTopBarLayerAlwaysVisible,
'The topBarWidget can only be set when isTopBarLayerAlwaysVisible is true.');

const animatedBuilderKey = ValueKey(WoltModalSheetPageTransitionState.incoming);
// If the page uses the default top bar, we should show the top bar title to be represented in
// the middle of the navigation toolbar.
final shouldShowTopBarTitle = hasTopBarLayer && _page.topBar == null;
Widget? navigationToolbarMiddle;
if (shouldShowTopBarTitle) {
navigationToolbarMiddle = isTopBarLayerAlwaysVisible
? Center(child: topBarTitle)
: WoltModalSheetTopBarTitleFlow(
page: _page,
currentScrollPositionListenable: _scrollPosition,
titleKey: _pageTitleKey,
topBarTitle: topBarTitle,
);
}
return PaginatingWidgetsGroup(
mainContentAnimatedBuilder: MainContentAnimatedBuilder(
key: animatedBuilderKey,
Expand All @@ -256,9 +266,7 @@ class _WoltModalSheetAnimatedSwitcherState extends State<WoltModalSheetAnimatedS
controller: animationController,
child: hasTopBarLayer
? (isTopBarLayerAlwaysVisible
? (_page.topBarWidget == null
? WoltModalSheetTopBar(page: _page)
: _page.topBarWidget!)
? WoltModalSheetTopBar(page: _page)
: WoltModalSheetTopBarFlow(
page: _page,
currentScrollPositionListenable: _scrollPosition,
Expand All @@ -276,16 +284,7 @@ class _WoltModalSheetAnimatedSwitcherState extends State<WoltModalSheetAnimatedS
child: WoltNavigationToolbar(
middleSpacing: 16.0,
leading: _page.leadingNavBarWidget,
middle: hasTopBarLayer
? (isTopBarLayerAlwaysVisible
? Center(child: topBarTitle)
: WoltModalSheetTopBarTitleFlow(
page: _page,
currentScrollPositionListenable: _scrollPosition,
titleKey: _pageTitleKey,
topBarTitle: topBarTitle,
))
: const SizedBox.shrink(),
middle: navigationToolbarMiddle,
trailing: _page.trailingNavBarWidget,
),
),
Expand Down
29 changes: 16 additions & 13 deletions lib/src/modal_page/wolt_modal_sheet_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ class WoltModalSheetPage {
/// text data, you should explicitly provide topBarTitle widget or set it as SizedBox.shrink().
final Widget? topBarTitle;

/// A [Widget] representing the top bar.
/// An optional [Widget] representing the top bar.
///
/// When provided this widget will be used as the top bar instead of the default top bar.
/// This can be used to provide a custom top bar with custom behavior only when
/// [isTopBarLayerAlwaysVisible] is set to true.
final Widget? topBarWidget;
/// When provided this widget will be used as the top bar instead of the default top bar. If
/// this widget is provided, the [topBarTitle] will not be displayed. The height of this
/// [topBar] should be set using the [navBarHeight] field.
final Widget? topBar;

/// On z axis, the Top Bar layer resides above the main content layer and below the transparent
/// navigation bar layer.
Expand Down Expand Up @@ -166,8 +166,11 @@ class WoltModalSheetPage {
this.trailingNavBarWidget,
this.hasTopBarLayer,
this.isTopBarLayerAlwaysVisible,
this.topBarWidget,
}) : assert((singleChildContent != null) == (sliverList == null));
this.topBar,
}) : assert((singleChildContent != null) == (sliverList == null),
"Either singleChildContent or sliverList must be provided"),
assert(!(topBar != null && hasTopBarLayer == false),
"When topBar is provided, hasTopBarLayer must not be false");

/// Creates a [WoltModalSheetPage] with a single child main content.
factory WoltModalSheetPage.withSingleChild({
Expand All @@ -188,7 +191,7 @@ class WoltModalSheetPage {
Widget? stickyActionBar,
Widget? leadingNavBarWidget,
Widget? trailingNavBarWidget,
Widget? topBarWidget,
Widget? topBar,
}) {
return WoltModalSheetPage(
singleChildContent: child,
Expand All @@ -208,7 +211,7 @@ class WoltModalSheetPage {
stickyActionBar: stickyActionBar,
leadingNavBarWidget: leadingNavBarWidget,
trailingNavBarWidget: trailingNavBarWidget,
topBarWidget: topBarWidget,
topBar: topBar,
);
}

Expand All @@ -231,7 +234,7 @@ class WoltModalSheetPage {
Widget? stickyActionBar,
Widget? leadingNavBarWidget,
Widget? trailingNavBarWidget,
Widget? topBarWidget,
Widget? topBar,
}) {
return WoltModalSheetPage(
sliverList: sliverList,
Expand All @@ -251,7 +254,7 @@ class WoltModalSheetPage {
stickyActionBar: stickyActionBar,
leadingNavBarWidget: leadingNavBarWidget,
trailingNavBarWidget: trailingNavBarWidget,
topBarWidget: topBarWidget,
topBar: topBar,
);
}

Expand All @@ -274,7 +277,7 @@ class WoltModalSheetPage {
Widget? stickyActionBar,
Widget? leadingNavBarWidget,
Widget? trailingNavBarWidget,
Widget? topBarWidget,
Widget? topBar,
}) {
return WoltModalSheetPage(
pageTitle: pageTitle ?? this.pageTitle,
Expand All @@ -295,7 +298,7 @@ class WoltModalSheetPage {
stickyActionBar: stickyActionBar ?? this.stickyActionBar,
leadingNavBarWidget: leadingNavBarWidget ?? this.leadingNavBarWidget,
trailingNavBarWidget: trailingNavBarWidget ?? this.trailingNavBarWidget,
topBarWidget: topBarWidget ?? this.topBarWidget,
topBar: topBar ?? this.topBar,
);
}
}
13 changes: 12 additions & 1 deletion playground/lib/home/pages/multi_page_path_name.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:playground/home/pages/root_sheet_page.dart';
import 'package:playground/home/pages/sheet_page_with_custom_top_bar.dart';
import 'package:playground/home/pages/sheet_page_with_dynamic_page_properties.dart';
import 'package:playground/home/pages/sheet_page_with_forced_max_height.dart';
import 'package:playground/home/pages/sheet_page_with_hero_image.dart';
Expand All @@ -15,6 +15,7 @@ enum MultiPagePathName {
lazyLoadingList(pageCount: 2, queryParamName: "lazyList"),
textField(pageCount: 2, queryParamName: "textField"),
noTitleNoTopBar(pageCount: 2, queryParamName: "noTitleNoTopBar"),
customTopBar(pageCount: 2, queryParamName: "customTopBar"),
dynamicPageProperties(pageCount: 2, queryParamName: "dynamicPageProperties"),
allPagesPath(pageCount: 6, queryParamName: "all");

Expand Down Expand Up @@ -66,6 +67,13 @@ enum MultiPagePathName {
onBackPressed: goToPreviousPage,
isLastPage: isLastPage,
);
WoltModalSheetPage customTopBar(BuildContext context, {bool isLastPage = true}) =>
SheetPageWithCustomTopBar.build(
onSabPressed: () => isLastPage ? close(context) : goToNextPage(),
onClosed: () => close(context),
onBackPressed: goToPreviousPage,
isLastPage: isLastPage,
);
WoltModalSheetPage dynamicPageProperties(BuildContext context, {bool isLastPage = true}) =>
SheetPageWithDynamicPageProperties.build(
onSabPressed: () => isLastPage ? close(context) : goToNextPage(),
Expand All @@ -92,6 +100,8 @@ enum MultiPagePathName {
return (context) => [root(context), textField(context)];
case MultiPagePathName.noTitleNoTopBar:
return (context) => [root(context), noTitleNoTopBar(context)];
case MultiPagePathName.customTopBar:
return (context) => [root(context), customTopBar(context)];
case MultiPagePathName.dynamicPageProperties:
return (context) => [root(context), dynamicPageProperties(context)];
case MultiPagePathName.allPagesPath:
Expand All @@ -101,6 +111,7 @@ enum MultiPagePathName {
lazyList(context, isLastPage: false),
textField(context, isLastPage: false),
noTitleNoTopBar(context, isLastPage: false),
customTopBar(context, isLastPage: false),
dynamicPageProperties(context, isLastPage: false),
forcedMaxHeight(context, isLastPage: true),
];
Expand Down
5 changes: 5 additions & 0 deletions playground/lib/home/pages/root_sheet_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ class RootSheetPage {
value: MultiPagePathName.textField,
isSelected: false,
),
WoltSelectionListItemData(
title: 'Page with custom top bar',
value: MultiPagePathName.customTopBar,
isSelected: false,
),
WoltSelectionListItemData(
title: 'Page with no title and no top bar',
value: MultiPagePathName.noTitleNoTopBar,
Expand Down
Loading

0 comments on commit aa99c21

Please sign in to comment.