-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fa5d558
commit f35979e
Showing
2 changed files
with
156 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import 'dart:io'; | ||
import 'package:flutter/cupertino.dart'; | ||
import 'package:flutter/material.dart'; | ||
|
||
class AppPage extends StatelessWidget { | ||
final String? title; | ||
final Widget? titleWidget; | ||
final List<Widget>? actions; | ||
final Widget? leading; | ||
final Widget? floatingActionButton; | ||
final Widget? body; | ||
final bool automaticallyImplyLeading; | ||
final bool? resizeToAvoidBottomInset; | ||
|
||
const AppPage({ | ||
super.key, | ||
this.title, | ||
this.titleWidget, | ||
this.actions, | ||
this.leading, | ||
this.body, | ||
this.floatingActionButton, | ||
this.resizeToAvoidBottomInset, | ||
this.automaticallyImplyLeading = true, | ||
}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
if (Platform.isIOS || Platform.isMacOS) { | ||
return _buildCupertinoScaffold(context); | ||
} else { | ||
return _buildMaterialScaffold(context); | ||
} | ||
} | ||
|
||
Widget _buildCupertinoScaffold(BuildContext context) => CupertinoPageScaffold( | ||
navigationBar: (title == null && titleWidget == null) && | ||
actions == null && | ||
leading == null | ||
? null | ||
: CupertinoNavigationBar( | ||
leading: leading, | ||
middle: titleWidget ?? _title(context), | ||
border: null, | ||
trailing: actions == null | ||
? null | ||
: actions!.length == 1 | ||
? actions!.first | ||
: Row( | ||
mainAxisSize: MainAxisSize.min, | ||
children: actions!, | ||
), | ||
automaticallyImplyLeading: automaticallyImplyLeading, | ||
previousPageTitle: automaticallyImplyLeading | ||
? MaterialLocalizations.of(context).backButtonTooltip | ||
: null, | ||
), | ||
resizeToAvoidBottomInset: resizeToAvoidBottomInset ?? true, | ||
child: Stack( | ||
alignment: Alignment.bottomRight, | ||
children: [ | ||
body ?? const SizedBox(), | ||
SafeArea( | ||
child: Padding( | ||
padding: const EdgeInsets.only(right: 16, bottom: 16), | ||
child: floatingActionButton ?? const SizedBox(), | ||
), | ||
), | ||
], | ||
), | ||
); | ||
|
||
Widget _buildMaterialScaffold(BuildContext context) => Scaffold( | ||
appBar: (title == null && titleWidget == null) && | ||
actions == null && | ||
leading == null | ||
? null | ||
: AppBar( | ||
title: titleWidget ?? _title(context), | ||
actions: actions, | ||
leading: leading, | ||
automaticallyImplyLeading: automaticallyImplyLeading, | ||
), | ||
body: body, | ||
floatingActionButton: floatingActionButton, | ||
resizeToAvoidBottomInset: resizeToAvoidBottomInset, | ||
); | ||
|
||
Widget _title(BuildContext context) => Text( | ||
title ?? '', | ||
maxLines: 1, | ||
overflow: TextOverflow.ellipsis, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import 'package:flutter/material.dart'; | ||
|
||
class ParallaxFlowDelegate extends FlowDelegate { | ||
ParallaxFlowDelegate({ | ||
required this.scrollable, | ||
required this.listItemContext, | ||
required this.backgroundImageKey, | ||
}) : super(repaint: scrollable.position); | ||
|
||
final ScrollableState scrollable; | ||
final BuildContext listItemContext; | ||
final GlobalKey backgroundImageKey; | ||
|
||
@override | ||
BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) { | ||
return BoxConstraints.tightFor( | ||
width: constraints.maxWidth, | ||
); | ||
} | ||
|
||
@override | ||
void paintChildren(FlowPaintingContext context) { | ||
// Ensure necessary objects are not null before proceeding | ||
final backgroundImageContext = backgroundImageKey.currentContext; | ||
if (backgroundImageContext == null) { | ||
return; | ||
} | ||
|
||
// Calculate the position of this list item within the viewport. | ||
final scrollableBox = scrollable.context.findRenderObject() as RenderBox; | ||
final listItemBox = listItemContext.findRenderObject() as RenderBox; | ||
final listItemOffset = listItemBox.localToGlobal( | ||
listItemBox.size.centerLeft(Offset.zero), | ||
ancestor: scrollableBox, | ||
); | ||
|
||
// Determine the percent position of this list item within the scrollable area. | ||
final viewportDimension = scrollable.position.viewportDimension; | ||
final scrollFraction = (listItemOffset.dy / viewportDimension).clamp(0.0, 1.0); | ||
|
||
// Calculate the vertical alignment of the background based on the scroll percent. | ||
final verticalAlignment = Alignment(0.0, scrollFraction * 2 - 1); | ||
|
||
// Convert the background alignment into a pixel offset for painting purposes. | ||
final backgroundSize = (backgroundImageContext.findRenderObject() as RenderBox).size; | ||
final listItemSize = context.size; | ||
final childRect = verticalAlignment.inscribe(backgroundSize, Offset.zero & listItemSize); | ||
|
||
// Paint the background. | ||
context.paintChild( | ||
0, | ||
transform: Transform.translate(offset: Offset(0.0, childRect.top)).transform, | ||
); | ||
} | ||
|
||
@override | ||
bool shouldRepaint(ParallaxFlowDelegate oldDelegate) { | ||
return scrollable != oldDelegate.scrollable || | ||
listItemContext != oldDelegate.listItemContext || | ||
backgroundImageKey != oldDelegate.backgroundImageKey; | ||
} | ||
} |