Skip to content

Commit

Permalink
Add PlatformSliverAppBar class with example
Browse files Browse the repository at this point in the history
  • Loading branch information
bookshiyi committed Jul 15, 2023
1 parent 3b89f46 commit fcedd7c
Show file tree
Hide file tree
Showing 4 changed files with 352 additions and 1 deletion.
14 changes: 14 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 @@ -385,6 +386,19 @@ 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))
Padding(
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,9 +36,10 @@ 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_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);
}

0 comments on commit fcedd7c

Please sign in to comment.