Long lists aren't obviously scrollable. Items just sit there and users don't know there's more.
Fading the edges signals that it scrolls. ShaderMask does this with no extra package:
ShaderMask (
shaderCallback : ( Rect bounds) {
return const LinearGradient (
begin : .topCenter,
end : .bottomCenter,
colors : [
Colors .transparent,
Colors .white,
Colors .white,
Colors .transparent,
],
stops : [ 0.0 , 0.12 , 0.88 , 1.0 ],
). createShader (bounds);
},
blendMode : .dstIn,
child : // your scrollable widget
)
Adjust stops to control the fade size. [0.0, 0.1, 0.9, 1.0] for subtle, [0.0, 0.3, 0.7, 1.0] for aggressive.
An example from expen.app , faded edges in a category picker:
Fading only the bottom edge usually works best. If they've scrolled down, they already know there's a top, they only need a hint that there's more below:
colors : [
Colors .white,
Colors .white,
Colors .white,
Colors .transparent,
],
stops : [ 0.0 , 0.0 , 0.88 , 1.0 ],
Or top only:
colors : [
Colors .transparent,
Colors .white,
Colors .white,
Colors .white,
],
stops : [ 0.0 , 0.12 , 1.0 , 1.0 ],
For horizontal lists, swap the gradient direction:
begin : .centerLeft,
end : .centerRight,
Or as a reusable widget:
class Edgy extends StatelessWidget {
final Widget child;
final Axis axis;
final bool fadeStart;
final bool fadeEnd;
const Edgy ({
super .key,
required this .child,
this .axis = .vertical,
this .fadeStart = true ,
this .fadeEnd = true ,
});
@override
Widget build ( BuildContext context) {
final bool isVertical = axis == .vertical;
return ShaderMask (
shaderCallback : ( Rect bounds) {
return LinearGradient (
begin : isVertical ? .topCenter : .centerLeft,
end : isVertical ? .bottomCenter : .centerRight,
colors : < Color > [
fadeStart ? const Color ( 0x00FFFFFF ) : const Color ( 0xFFFFFFFF ),
const Color ( 0xFFFFFFFF ),
const Color ( 0xFFFFFFFF ),
fadeEnd ? const Color ( 0x00FFFFFF ) : const Color ( 0xFFFFFFFF ),
],
stops : < double > [ 0.0 , 0.12 , 0.88 , 1.0 ],
). createShader (bounds);
},
blendMode : .dstIn,
child : child,
);
}
}
The mask is alpha-only, so this works the same in light and dark mode.