feat(#173): dégradés haut/bas sur la liste de bulles scrollable
Même logique que le slider enfants : fondu aux bords sauf au premier et au dernier élément. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -22,17 +22,32 @@ class CartesFeed extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _CartesFeedState extends State<CartesFeed> {
|
||||
static const double _fadeExtent = 0.08;
|
||||
|
||||
List<CarteBulle> _items = const [];
|
||||
bool _loading = true;
|
||||
String? _error;
|
||||
String? _busyCardId;
|
||||
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
bool _isScrollable = false;
|
||||
bool _fadeTop = false;
|
||||
bool _fadeBottom = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_scrollController.addListener(_syncScrollFades);
|
||||
_load();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.removeListener(_syncScrollFades);
|
||||
_scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant CartesFeed oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
@@ -41,6 +56,25 @@ class _CartesFeedState extends State<CartesFeed> {
|
||||
}
|
||||
}
|
||||
|
||||
void _syncScrollFades() {
|
||||
if (!_scrollController.hasClients) return;
|
||||
final position = _scrollController.position;
|
||||
final scrollable = position.maxScrollExtent > 0.0;
|
||||
final threshold = position.viewportDimension * _fadeExtent / 2;
|
||||
final fadeTop = scrollable && position.pixels > threshold;
|
||||
final fadeBottom = scrollable &&
|
||||
position.pixels < (position.maxScrollExtent - threshold);
|
||||
if (scrollable != _isScrollable ||
|
||||
fadeTop != _fadeTop ||
|
||||
fadeBottom != _fadeBottom) {
|
||||
setState(() {
|
||||
_isScrollable = scrollable;
|
||||
_fadeTop = fadeTop;
|
||||
_fadeBottom = fadeBottom;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _load() async {
|
||||
setState(() {
|
||||
_loading = true;
|
||||
@@ -55,6 +89,7 @@ class _CartesFeedState extends State<CartesFeed> {
|
||||
_items = items;
|
||||
_loading = false;
|
||||
});
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _syncScrollFades());
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
@@ -304,10 +339,52 @@ class _CartesFeedState extends State<CartesFeed> {
|
||||
);
|
||||
}
|
||||
|
||||
return RefreshIndicator(
|
||||
return NotificationListener<ScrollMetricsNotification>(
|
||||
onNotification: (_) {
|
||||
_syncScrollFades();
|
||||
return false;
|
||||
},
|
||||
child: ShaderMask(
|
||||
blendMode: BlendMode.dstIn,
|
||||
shaderCallback: (Rect bounds) {
|
||||
final stops = <double>[
|
||||
0.0,
|
||||
_fadeExtent,
|
||||
1.0 - _fadeExtent,
|
||||
1.0,
|
||||
];
|
||||
if (!_isScrollable) {
|
||||
return const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: <Color>[
|
||||
Colors.black,
|
||||
Colors.black,
|
||||
Colors.black,
|
||||
Colors.black,
|
||||
],
|
||||
stops: [0.0, 0.08, 0.92, 1.0],
|
||||
).createShader(bounds);
|
||||
}
|
||||
final topMask = _fadeTop ? Colors.transparent : Colors.black;
|
||||
final bottomMask = _fadeBottom ? Colors.transparent : Colors.black;
|
||||
return LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: <Color>[
|
||||
topMask,
|
||||
Colors.black,
|
||||
Colors.black,
|
||||
bottomMask,
|
||||
],
|
||||
stops: stops,
|
||||
).createShader(bounds);
|
||||
},
|
||||
child: RefreshIndicator(
|
||||
onRefresh: _load,
|
||||
child: ListView.separated(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
controller: _scrollController,
|
||||
padding: const EdgeInsets.only(top: 4, bottom: 8),
|
||||
itemCount: _items.length,
|
||||
separatorBuilder: (_, __) => const SizedBox(height: 10),
|
||||
itemBuilder: (context, index) {
|
||||
@@ -321,6 +398,8 @@ class _CartesFeedState extends State<CartesFeed> {
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user