Last active
January 8, 2025 09:27
-
-
Save smkhalsa/ec33ec61993f29865a52a40fff4b81a2 to your computer and use it in GitHub Desktop.
A Widget that automatically fades its child based on scroll position
This file contains hidden or 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
import 'package:flutter/material.dart'; | |
class FadeOnScroll extends StatefulWidget { | |
final ScrollController scrollController; | |
final double zeroOpacityOffset; | |
final double fullOpacityOffset; | |
final Widget child; | |
FadeOnScroll( | |
{Key key, | |
@required this.scrollController, | |
@required this.child, | |
this.zeroOpacityOffset = 0, | |
this.fullOpacityOffset = 0}); | |
@override | |
_FadeOnScrollState createState() => _FadeOnScrollState(); | |
} | |
class _FadeOnScrollState extends State<FadeOnScroll> { | |
double _offset; | |
@override | |
initState() { | |
super.initState(); | |
_offset = widget.scrollController.offset; | |
widget.scrollController.addListener(_setOffset); | |
} | |
@override | |
dispose() { | |
widget.scrollController.removeListener(_setOffset); | |
super.dispose(); | |
} | |
void _setOffset() { | |
setState(() { | |
_offset = widget.scrollController.offset; | |
}); | |
} | |
double _calculateOpacity() { | |
if (widget.fullOpacityOffset == widget.zeroOpacityOffset) | |
return 1; | |
else if (widget.fullOpacityOffset > widget.zeroOpacityOffset) { | |
// fading in | |
if (_offset <= widget.zeroOpacityOffset) | |
return 0; | |
else if (_offset >= widget.fullOpacityOffset) | |
return 1; | |
else | |
return (_offset - widget.zeroOpacityOffset) / (widget.fullOpacityOffset - widget.zeroOpacityOffset); | |
} else { | |
// fading out | |
if (_offset <= widget.fullOpacityOffset) | |
return 1; | |
else if (_offset >= widget.zeroOpacityOffset) | |
return 0; | |
else | |
return (_offset - widget.fullOpacityOffset) / (widget.zeroOpacityOffset - widget.fullOpacityOffset); | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Opacity( | |
opacity: _calculateOpacity(), | |
child: widget.child, | |
); | |
} | |
} |
This file contains hidden or 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
import 'package:flutter/material.dart'; | |
import './fade_on_scroll.dart'; | |
class FadingWidgetExample extends StatelessWidget { | |
final ScrollController scrollController = ScrollController(); | |
@override | |
Widget build(BuildContext context) { | |
return CustomScrollView( | |
controller: scrollController, | |
slivers: <Widget>[ | |
SliverAppBar( | |
pinned: true, | |
title: FadeOnScroll( | |
scrollController: scrollController, | |
fullOpacityOffset: 180, | |
child: Text("I'm going to fade"), | |
), | |
), | |
SliverList( | |
delegate: | |
SliverChildBuilderDelegate((BuildContext context, int index) { | |
return ListTile( | |
title: Text('Row $index'), | |
); | |
}), | |
) | |
], | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Great gist and code. But fade out part does not work correctly, because we need to return (1 - calculated) for fade out logic. Because you're using an opacity widget, you need to complement that value to 1 so that it works as expected/needed.