Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@smkhalsa
Last active November 29, 2023 03:00
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save smkhalsa/ec33ec61993f29865a52a40fff4b81a2 to your computer and use it in GitHub Desktop.
Save smkhalsa/ec33ec61993f29865a52a40fff4b81a2 to your computer and use it in GitHub Desktop.
A Widget that automatically fades its child based on scroll position
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,
);
}
}
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'),
);
}),
)
],
);
}
}
@codewithmustafa
Copy link

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.

else {
      // fading out
      if (_offset <= widget.fullOpacityOffset) {
        return 1;
      } else if (_offset >= widget.zeroOpacityOffset) {
        return 0;
      } else {
        return 1 -
            (_offset - widget.fullOpacityOffset) /
                (widget.zeroOpacityOffset - widget.fullOpacityOffset);
      }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment