Skip to content

Instantly share code, notes, and snippets.

@jelenalecic
Created June 18, 2021 19:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jelenalecic/5714da24e69e289dd9b78e35a4c41cc5 to your computer and use it in GitHub Desktop.
Save jelenalecic/5714da24e69e289dd9b78e35a4c41cc5 to your computer and use it in GitHub Desktop.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
void main() {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return App();
}
}
class App extends StatefulWidget {
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
ScrollController _scrollController = ScrollController();
bool _isScrolling = false;
StreamController<FiltersState> _filtersStateController =
StreamController<FiltersState>.broadcast();
@override
void dispose() {
super.dispose();
_filtersStateController.close();
_scrollController.dispose();
}
@override
void initState() {
super.initState();
_scrollController.addListener(() {
if (!_isScrolling) {
_isScrolling = true;
if (_scrollController.position.userScrollDirection ==
ScrollDirection.forward) {
_filtersStateController.add(FiltersState.collapsed);
} else {
_filtersStateController.add(FiltersState.hidden);
}
}
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: NotificationListener(
onNotification: (notificationInfo) {
if (notificationInfo is ScrollEndNotification) {
_isScrolling = false;
}
return true;
},
child: Scaffold(
body: SafeArea(
child: Column(
children: [
Filters(stateController: _filtersStateController),
Flexible(
child: ListView.builder(
controller: _scrollController,
itemCount: 50,
itemBuilder: (BuildContext context, int index) =>
Container(
alignment: Alignment.center,
margin: EdgeInsets.symmetric(
horizontal: 20, vertical: 10),
height: 70,
decoration: BoxDecoration(
color: Colors.blueGrey
.withOpacity(1 - (1 / 50) * index),
borderRadius: BorderRadius.all(
Radius.circular(4),
)),
child: Text(
'item $index'.toUpperCase(),
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
)),
)
],
),
),
),
));
}
}
enum FiltersState { hidden, collapsed, expanded }
class Filters extends StatefulWidget {
const Filters({required this.stateController});
final StreamController<FiltersState> stateController;
@override
_FiltersState createState() => _FiltersState();
}
class _FiltersState extends State<Filters> {
FiltersState _state = FiltersState.collapsed;
@override
void initState() {
super.initState();
widget.stateController.stream.listen((FiltersState newState) {
if (_state != newState) {
setState(() {
_state = newState;
});
}
});
}
@override
Widget build(BuildContext context) {
return AnimatedSwitcher(
switchInCurve: Curves.easeOut,
switchOutCurve: Curves.easeIn,
duration: Duration(milliseconds: 500),
transitionBuilder: (Widget child, Animation<double> animation) {
return SizeTransition(
sizeFactor: animation,
child: SlideTransition(
position: Tween<Offset>(begin: Offset(0, -1), end: Offset(0, 0))
.animate(animation),
child: child,
),
);
},
child: _state == FiltersState.hidden
? Container()
: AnimatedContainer(
alignment: Alignment.center,
margin: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
decoration: BoxDecoration(
color: _getColor(),
borderRadius: BorderRadius.all(
Radius.circular(_state == FiltersState.collapsed ? 30 : 10),
)),
width: double.infinity,
duration: Duration(milliseconds: 700),
curve: _state == FiltersState.collapsed
? Curves.easeIn
: Curves.decelerate,
height: _getHeight(),
child: Material(
color: Colors.transparent,
child: InkWell(
splashColor: Colors.orange,
onTap: () {
setState(() {
if (_state == FiltersState.collapsed) {
_state = FiltersState.expanded;
} else if (_state == FiltersState.expanded) {
_state = FiltersState.collapsed;
}
});
},
child: _getWidget()),
),
),
);
}
double _getHeight() {
switch (_state) {
case FiltersState.hidden:
return 0;
case FiltersState.collapsed:
return 120;
case FiltersState.expanded:
return 300;
}
}
Color _getColor() {
switch (_state) {
case FiltersState.hidden:
return Colors.transparent;
case FiltersState.collapsed:
return Colors.pink;
case FiltersState.expanded:
return Colors.purple;
}
}
Widget _getWidget() {
switch (_state) {
case FiltersState.hidden:
return Container();
case FiltersState.expanded:
return _getExpandedWidget();
case FiltersState.collapsed:
return _getCollapsedWidget();
}
}
Widget _getExpandedWidget() {
return _getSimpleText('Expanded filters');
}
Widget _getCollapsedWidget() {
return _getSimpleText('Collapsed filters');
}
Widget _getSimpleText(String text) {
return Center(
child: Text(
text.toUpperCase(),
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 35,
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment