garage_auth, garage_entitlements, garage_iap and garage_ui, moved out of Garage-Services and Metro-Map-Maker into one public repo. MIT, one readme, docs under docs/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013F4NWNvYcdeSgqbWMT1VQ7
45 lines
1.6 KiB
Dart
45 lines
1.6 KiB
Dart
import "package:flutter/widgets.dart";
|
|
|
|
/// Wraps a scrollable panel body so content approaching the top or bottom
|
|
/// edge fades to transparent over [fadeExtent] pixels instead of getting cut
|
|
/// off flat by the scroll view's own default hard clip. Purely a paint
|
|
/// effect - the scroll views clip still keeps everything contained, this
|
|
/// just masks the alpha near each edge on top of that.
|
|
///
|
|
/// Colour-blind on purpose: the gradient only carries alpha (dstIn blends
|
|
/// against whatever's already painted), so it works unchanged over any panel
|
|
/// background/scheme rather than needing its own colour token.
|
|
class ScrollEdgeFade extends StatelessWidget {
|
|
const ScrollEdgeFade({super.key, required this.child, this.fadeExtent = 6});
|
|
|
|
final Widget child;
|
|
final double fadeExtent;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ShaderMask(
|
|
shaderCallback: (bounds) {
|
|
// fraction of the box height the fade eats into from each end - a
|
|
// fixed pixel extent thats clamped so a very short panel doesnt end
|
|
// up with the two fades overlapping and cancelling out the middle.
|
|
final fraction = bounds.height > 0
|
|
? (fadeExtent / bounds.height).clamp(0.0, 0.5)
|
|
: 0.0;
|
|
return LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
stops: [0.0, fraction, 1 - fraction, 1.0],
|
|
colors: const [
|
|
Color(0x00ffffff),
|
|
Color(0xffffffff),
|
|
Color(0xffffffff),
|
|
Color(0x00ffffff),
|
|
],
|
|
).createShader(bounds);
|
|
},
|
|
blendMode: BlendMode.dstIn,
|
|
child: child,
|
|
);
|
|
}
|
|
}
|