Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PlatformSliverAppBar class with example #427

Merged
merged 2 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions example/lib/platform_page.dart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'logo.dart';
import 'material_ios_page.dart';
import 'platform_widget_example.dart';
import 'tab_impl_page.dart';
import 'sliver_app_bar_page.dart';

class PlatformPage extends StatelessWidget {
@override
Expand Down Expand Up @@ -374,6 +375,22 @@ class PlatformPage extends StatelessWidget {
),
),
),
),
// ! Platform Sliver AppBar
Padding(
padding: const EdgeInsets.all(8.0),
child: PlatformElevatedButton(
child: Text('Show Sliver AppBar Page'),
onPressed: () => Navigator.of(context).push(
platformPageRoute(
context: context,
builder: (context) => PlatformSliverAppBarPage(),
),
),
),
),
// ! Material on iOS
if (isCupertino(context))
// ! Icons
Padding(
padding: const EdgeInsets.all(8.0),
Expand Down
39 changes: 39 additions & 0 deletions example/lib/sliver_app_bar_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';

class PlatformSliverAppBarPage extends StatefulWidget {
const PlatformSliverAppBarPage({super.key});

@override
State<PlatformSliverAppBarPage> createState() =>
_PlatformSliverAppBarPageState();
}

class _PlatformSliverAppBarPageState extends State<PlatformSliverAppBarPage> {
@override
Widget build(BuildContext context) {
return PlatformScaffold(
body: CustomScrollView(
slivers: <Widget>[
PlatformSliverAppBar(
title: Text('Sliver App Bar'),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
color: index.isOdd ? Colors.white : Colors.black12,
height: 100.0,
child: Center(
child: PlatformText('$index', textScaleFactor: 5),
),
);
},
childCount: 20,
),
),
],
),
);
}
}
3 changes: 2 additions & 1 deletion lib/flutter_platform_widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ export 'src/platform_page_route.dart';
export 'src/platform_popup_menu.dart';
export 'src/platform_provider.dart';
export 'src/platform_radio.dart';
export 'src/platform_search_bar.dart';
export 'src/platform_scaffold.dart';
export 'src/platform_search_bar.dart';
export 'src/platform_scrollbar.dart';
export 'src/platform_slider.dart';
export 'src/platform_sliver_app_bar.dart';
export 'src/platform_switch.dart';
export 'src/platform_tab_scaffold.dart';
export 'src/platform_text.dart';
Expand Down
297 changes: 297 additions & 0 deletions lib/src/platform_sliver_app_bar.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
/*
* flutter_platform_widgets
* Copyright (c) 2018 Lance Johnstone. All rights reserved.
* See LICENSE for distribution and usage details.
*/

import 'package:flutter/cupertino.dart'
show CupertinoSliverNavigationBar, Brightness;
import 'package:flutter/material.dart'
show SliverAppBar, kToolbarHeight; //MaterialStateProperty, ;
import 'package:flutter/widgets.dart';
import 'package:flutter/foundation.dart' show AsyncCallback;
import 'package:flutter/services.dart' show SystemUiOverlayStyle;
import 'platform.dart';
import 'widget_base.dart';

abstract class _BaseData {
_BaseData({
//Common
this.widgetKey,
this.leading,
this.automaticallyImplyLeading,
this.backgroundColor,
this.stretch,
this.title,
});

final Key? widgetKey;
final Widget? leading;
final bool? automaticallyImplyLeading;
final Color? backgroundColor;
final bool? stretch;
final Widget? title;
}

class MaterialSliverAppBarData extends _BaseData {
MaterialSliverAppBarData({
// Common
super.widgetKey,
super.leading,
super.automaticallyImplyLeading,
super.backgroundColor,
super.stretch,
super.title,

//Material
this.actions,
this.flexibleSpace,
this.bottom,
this.elevation,
this.scrolledUnderElevation,
this.shadowColor,
this.surfaceTintColor,
this.forceElevated = false,
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.stretchTriggerOffset = 100.0,
this.onStretchTrigger,
this.shape,
this.toolbarHeight = kToolbarHeight,
this.leadingWidth,
this.toolbarTextStyle,
this.titleTextStyle,
this.systemOverlayStyle,
this.forceMaterialTransparency = false,
this.clipBehavior,
}) : 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].');

// final Widget? title;
final List<Widget>? actions;
final Widget? flexibleSpace;
final PreferredSizeWidget? bottom;
final double? elevation;
final double? scrolledUnderElevation;
final Color? shadowColor;
final Color? surfaceTintColor;
final bool forceElevated;
final Color? foregroundColor;
final IconThemeData? iconTheme;
final IconThemeData? actionsIconTheme;
final bool primary;
final bool? centerTitle;
final bool excludeHeaderSemantics;
final double? titleSpacing;
final double? collapsedHeight;
final double? expandedHeight;
final bool floating;
final bool pinned;
final ShapeBorder? shape;
final bool snap;
final double stretchTriggerOffset;
final AsyncCallback? onStretchTrigger;
final double toolbarHeight;
final double? leadingWidth;
final TextStyle? toolbarTextStyle;
final TextStyle? titleTextStyle;
final SystemUiOverlayStyle? systemOverlayStyle;
final bool forceMaterialTransparency;
final Clip? clipBehavior;
}

class CupertinoSliverAppBarData extends _BaseData {
CupertinoSliverAppBarData({
//Common
super.widgetKey,
super.leading,
super.automaticallyImplyLeading,
super.backgroundColor,
super.stretch,
super.title,

//Cupertino
// this.largeTitle,
this.automaticallyImplyTitle = true,
this.alwaysShowMiddle = true,
this.previousPageTitle,
this.middle,
this.trailing,
this.border = _kDefaultNavBarBorder,
this.brightness,
this.padding,
this.transitionBetweenRoutes = true,
this.heroTag = _defaultHeroTag,
}) : assert(
automaticallyImplyTitle == true || title != null,
'No title has been provided but automaticallyImplyTitle is also '
'false. Either provide a title or set automaticallyImplyTitle to '
'true.',
);

// final Widget? largeTitle;
final bool automaticallyImplyTitle;
final bool alwaysShowMiddle;
final String? previousPageTitle;
final Widget? middle;
final Widget? trailing;
final Brightness? brightness;
final EdgeInsetsDirectional? padding;
final Border? border;
final bool transitionBetweenRoutes;
final Object heroTag;
}

class PlatformSliverAppBar
extends PlatformWidgetBase<CupertinoSliverNavigationBar, SliverAppBar> {
//Common
final Key? widgetKey;

final Widget? leading;
final bool? automaticallyImplyLeading;
final Color? backgroundColor;
final bool? stretch;
final Widget? title;

//Platform
final PlatformBuilder<MaterialSliverAppBarData>? material;
final PlatformBuilder<CupertinoSliverAppBarData>? cupertino;

PlatformSliverAppBar({
//Common
super.key,
this.widgetKey,
this.leading,
this.automaticallyImplyLeading,
this.backgroundColor,
this.stretch,
this.title,
//Platform
this.material,
this.cupertino,
});

@override
SliverAppBar createMaterialWidget(BuildContext context) {
final data = material?.call(context, platform(context));
return SliverAppBar(
//Common
key: data?.widgetKey ?? widgetKey,
leading: data?.leading ?? leading,
automaticallyImplyLeading:
data?.automaticallyImplyLeading ?? automaticallyImplyLeading ?? true,
backgroundColor: data?.backgroundColor ?? backgroundColor,
stretch: data?.stretch ?? stretch ?? false,
title: data?.title ?? title,

//Material only
actions: data?.actions,
flexibleSpace: data?.flexibleSpace,
bottom: data?.bottom,
elevation: data?.elevation,
shadowColor: data?.shadowColor,
forceElevated: data?.forceElevated ?? false,
foregroundColor: data?.foregroundColor,
iconTheme: data?.iconTheme,
actionsIconTheme: data?.actionsIconTheme,
primary: data?.primary ?? true,
centerTitle: data?.centerTitle,
excludeHeaderSemantics: data?.excludeHeaderSemantics ?? false,
titleSpacing: data?.titleSpacing,
collapsedHeight: data?.collapsedHeight,
expandedHeight: data?.expandedHeight,
floating: data?.floating ?? false,
pinned: data?.pinned ?? false,
snap: data?.snap ?? false,
stretchTriggerOffset: data?.stretchTriggerOffset ?? 100.0,
onStretchTrigger: data?.onStretchTrigger,
shape: data?.shape,
toolbarHeight: data?.toolbarHeight ?? kToolbarHeight,
leadingWidth: data?.leadingWidth,
toolbarTextStyle: data?.toolbarTextStyle,
titleTextStyle: data?.titleTextStyle,
systemOverlayStyle: data?.systemOverlayStyle,
forceMaterialTransparency: data?.forceMaterialTransparency ?? false,
clipBehavior: data?.clipBehavior,
);
}

@override
CupertinoSliverNavigationBar createCupertinoWidget(BuildContext context) {
final data = cupertino?.call(context, platform(context));

return CupertinoSliverNavigationBar(
//Common
key: data?.widgetKey ?? widgetKey,
leading: data?.leading ?? leading,
automaticallyImplyLeading:
data?.automaticallyImplyLeading ?? automaticallyImplyLeading ?? true,
backgroundColor: data?.backgroundColor ?? backgroundColor,
stretch: data?.stretch ?? stretch ?? false,
largeTitle: data?.title ?? title,

//Cupertino only
automaticallyImplyTitle: data?.automaticallyImplyTitle ?? true,
alwaysShowMiddle: data?.alwaysShowMiddle ?? true,
previousPageTitle: data?.previousPageTitle,
middle: data?.middle,
trailing: data?.trailing,
border: data?.border ?? _kDefaultNavBarBorder,
brightness: data?.brightness,
padding: data?.padding,
transitionBetweenRoutes: data?.transitionBetweenRoutes ?? true,
heroTag: data?.heroTag ?? _defaultHeroTag,
);
}
}

//! Copied from file: /opt/homebrew/Caskroom/flutter/3.10.0/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart
const Color _kDefaultNavBarBorderColor = Color(0x4D000000);

const Border _kDefaultNavBarBorder = Border(
bottom: BorderSide(
color: _kDefaultNavBarBorderColor,
width: 0.0, // 0.0 means one physical pixel
),
);

const _HeroTag _defaultHeroTag = _HeroTag(null);

@immutable
class _HeroTag {
const _HeroTag(this.navigator);

final NavigatorState? navigator;

// Let the Hero tag be described in tree dumps.
@override
String toString() =>
'Default Hero tag for Cupertino navigation bars with navigator $navigator';

@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (other.runtimeType != runtimeType) {
return false;
}
return other is _HeroTag && other.navigator == navigator;
}

@override
int get hashCode => identityHashCode(navigator);
}
Comment on lines +261 to +297
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding these local variables, I didn't find a better solution, so I had to copy and paste them here intact.