fooder-app/lib/components/sliver.dart

173 lines
3.9 KiB
Dart
Raw Normal View History

2024-03-28 16:25:49 +01:00
import 'package:flutter/material.dart';
2024-03-29 16:47:25 +01:00
import 'package:blur/blur.dart';
class ClipShadowPath extends StatelessWidget {
final Shadow shadow;
final CustomClipper<Path> clipper;
final Widget child;
2024-03-30 14:07:10 +01:00
const ClipShadowPath({
super.key,
2024-03-29 16:47:25 +01:00
required this.shadow,
required this.clipper,
required this.child,
});
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: _ClipShadowShadowPainter(
2024-03-30 14:07:10 +01:00
clipper: clipper,
shadow: shadow,
2024-03-29 16:47:25 +01:00
),
2024-03-30 14:07:10 +01:00
child: ClipPath(clipper: clipper, child: child),
2024-03-29 16:47:25 +01:00
);
}
}
class _ClipShadowShadowPainter extends CustomPainter {
final Shadow shadow;
final CustomClipper<Path> clipper;
_ClipShadowShadowPainter({required this.shadow, required this.clipper});
@override
void paint(Canvas canvas, Size size) {
var paint = shadow.toPaint();
var clipPath = clipper.getClip(size).shift(shadow.offset);
canvas.drawPath(clipPath, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
2024-03-28 16:25:49 +01:00
class BackgroundWave extends StatelessWidget {
final double height;
2024-03-30 14:07:10 +01:00
const BackgroundWave({super.key, required this.height});
2024-03-28 16:25:49 +01:00
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
var colorScheme = theme.colorScheme;
return SizedBox(
height: height,
2024-03-29 16:47:25 +01:00
child: ClipShadowPath(
clipper: BackgroundWaveClipper(),
shadow: BoxShadow(
blurRadius: 5,
color: colorScheme.primary.withOpacity(0.3),
offset: const Offset(0, 5),
),
child: Blur(
blur: 10,
blurColor: colorScheme.primary.withOpacity(0.1),
2024-03-28 16:25:49 +01:00
child: Container(
width: MediaQuery.of(context).size.width,
height: height,
decoration: BoxDecoration(
2024-03-29 16:47:25 +01:00
gradient: LinearGradient(
colors: [
colorScheme.primary.withOpacity(0.1),
colorScheme.secondary.withOpacity(0.1),
],
),
),
),
),
),
2024-03-28 16:25:49 +01:00
);
}
}
class BackgroundWaveClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path();
path.lineTo(0.0, size.height);
var firstCurve = Offset(0, size.height - 20);
2024-03-29 16:47:25 +01:00
var lastCurve = Offset(40, size.height - 20);
2024-03-28 16:25:49 +01:00
path.quadraticBezierTo(
2024-03-30 14:07:10 +01:00
firstCurve.dx,
firstCurve.dy,
lastCurve.dx,
lastCurve.dy,
2024-03-28 16:25:49 +01:00
);
firstCurve = Offset(0, size.height - 20);
2024-03-29 16:47:25 +01:00
lastCurve = Offset(size.width - 40, size.height - 20);
2024-03-28 16:25:49 +01:00
path.quadraticBezierTo(
2024-03-30 14:07:10 +01:00
firstCurve.dx,
firstCurve.dy,
lastCurve.dx,
lastCurve.dy,
2024-03-28 16:25:49 +01:00
);
firstCurve = Offset(size.width, size.height - 20);
lastCurve = Offset(size.width, size.height);
path.quadraticBezierTo(
2024-03-30 14:07:10 +01:00
firstCurve.dx,
firstCurve.dy,
lastCurve.dx,
lastCurve.dy,
2024-03-28 16:25:49 +01:00
);
path.lineTo(size.width, 0.0);
path.close();
return path;
}
@override
bool shouldReclip(BackgroundWaveClipper oldClipper) => oldClipper != this;
}
class FSliverAppBar extends SliverPersistentHeaderDelegate {
final Widget child;
const FSliverAppBar({required this.child});
@override
2024-03-30 14:07:10 +01:00
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
var adjustedShrinkOffset =
shrinkOffset > minExtent ? minExtent : shrinkOffset;
2024-03-28 16:25:49 +01:00
double offset = (minExtent - adjustedShrinkOffset);
2024-03-29 16:47:25 +01:00
if (offset < 4) {
offset = 4;
}
2024-03-28 16:25:49 +01:00
return Stack(
children: [
const BackgroundWave(
height: 280,
),
Positioned(
2024-03-29 16:47:25 +01:00
top: offset,
2024-03-28 16:25:49 +01:00
left: 16,
right: 16,
2024-03-30 14:07:10 +01:00
child: child,
2024-03-28 16:25:49 +01:00
)
],
);
}
@override
double get maxExtent => 280;
@override
double get minExtent => 140;
@override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) =>
oldDelegate.maxExtent != maxExtent || oldDelegate.minExtent != minExtent;
}