fix: improve scroll handling on home page to avoid unintentional scroll event detection

This commit is contained in:
Michael Thomas 2023-02-09 20:00:05 -05:00
parent 67efdc0289
commit aed14e8159
5 changed files with 128 additions and 64 deletions

View File

@ -8,9 +8,11 @@ import 'package:furman_now/src/widgets/scroll_view_height.dart';
class HomeContent extends StatefulWidget {
final bool collapse;
final ScrollController controller;
const HomeContent({
required this.collapse,
required this.controller,
Key? key,
}) : super(key: key);
@ -19,13 +21,12 @@ class HomeContent extends StatefulWidget {
}
class _HomeContentState extends State<HomeContent> {
final ScrollController _controller = ScrollController();
bool _collapse = false;
@override
Widget build(BuildContext context) {
if (widget.collapse != _collapse) {
_controller.animateTo(
widget.controller.animateTo(
0,
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
@ -35,7 +36,7 @@ class _HomeContentState extends State<HomeContent> {
return LayoutBuilder(
builder: (context, constraints) => ScrollViewWithHeight(
controller: _controller,
controller: widget.controller,
child: Align(
alignment: Alignment.bottomCenter,
child: TweenAnimationBuilder<double>(
@ -50,7 +51,10 @@ class _HomeContentState extends State<HomeContent> {
decoration: const BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.vertical(top: Radius.circular(30)),
BorderRadius.vertical(
top: Radius.circular(30),
bottom: Radius.circular(30),
),
),
padding: const EdgeInsets.only(bottom: 15),
margin: EdgeInsets.only(top: margin),

View File

@ -44,6 +44,7 @@ class HomePageHeader extends StatelessWidget {
color: Color(0xff26183d),
fontSize: 36,
fontWeight: FontWeight.w800,
height: 1.2,
)),
),
),

View File

@ -1,5 +1,6 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:furman_now/src/routes/index.gr.dart';
import 'package:furman_now/src/screens/home/content.dart';
import 'package:furman_now/src/screens/home/state.dart';
@ -13,75 +14,124 @@ class HomeScreen extends StatefulWidget {
}
class _HomeScreenState extends State<HomeScreen> {
bool _collapse = false;
final ScrollController _controller = ScrollController();
double overscrollTopAmount = 0;
double overscrollBottomAmount = 0;
@override
void initState() {
super.initState();
_controller.addListener(updateScrollPosition);
}
updateScrollPosition() {
// bottom overscroll
if (_controller.position.pixels > _controller.position.maxScrollExtent) {
setState(() {
overscrollBottomAmount =
_controller.position.pixels - _controller.position.maxScrollExtent;
});
} else {
if (overscrollBottomAmount != 0) {
setState(() {
overscrollBottomAmount = 0;
});
}
}
// top overscroll
if (_controller.position.pixels < 0) {
setState(() {
overscrollTopAmount =
_controller.position.pixels.abs();
});
} else {
if (overscrollTopAmount != 0) {
setState(() {
overscrollTopAmount = 0;
});
}
}
}
handleScrollEvent(BuildContext context) {
const scrollMessageSensitivity = 20;
const pageSwitchSensitivity = 60;
var offsetAmount = overscrollTopAmount.abs();
if (overscrollTopAmount != 0) {
if (offsetAmount > pageSwitchSensitivity) {
context.router.navigate(const StudentIdRoute());
context.read<HomePageState>().collapse = true;
} else if (offsetAmount > scrollMessageSensitivity) {
context.read<HomePageState>().showScrollMessage = true;
} else {
context.read<HomePageState>().showScrollMessage = false;
}
} else {
context.read<HomePageState>().showScrollMessage = false;
if (_controller.position.pixels > pageSwitchSensitivity) {
context.router.navigate(const HomeRoute());
context.read<HomePageState>().collapse = false;
}
}
}
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => HomePageState(),
builder: (context, _) => Scaffold(
body: Container(
color: const Color(0xffb7acc9),
child: SafeArea(
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: Container(
color: const Color(0xffb7acc9),
child: Stack(
fit: StackFit.loose,
children: [
const AutoTabsRouter(
routes: [
HomeRoute(),
StudentIdRoute(),
child: SafeArea(
child: Container(
color: const Color(0xffb7acc9),
child: Stack(
fit: StackFit.loose,
children: [
// overscroll indicator color
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: overscrollBottomAmount + 30,
color: Colors.grey.shade50,
),
),
const AutoTabsRouter(
routes: [
HomeRoute(),
StudentIdRoute(),
],
),
NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (notification is ScrollUpdateNotification) {
handleScrollEvent(context);
}
return true;
},
child: Consumer<HomePageState>(
builder: (context, state, _) =>
ClipRect(child: HomeContent(
controller: _controller,
collapse: state.collapse,
),
),
),
),
],
),
NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (notification is ScrollUpdateNotification) {
final offset = notification.metrics.pixels;
const scrollMessageSensitivity = 20;
const pageSwitchSensitivity = 60;
if (offset < 0) {
var offsetAmount = offset.abs();
if (offsetAmount > pageSwitchSensitivity) {
context.router.navigate(const StudentIdRoute());
setState(() {
_collapse = true;
});
} else if (offsetAmount > scrollMessageSensitivity) {
if (!context.read<HomePageState>().showScrollMessage) {
context.read<HomePageState>().showScrollMessage = true;
}
} else {
if (context.read<HomePageState>().showScrollMessage) {
context.read<HomePageState>().showScrollMessage = false;
}
}
} else {
var offsetAmount = offset.abs();
if (offsetAmount > pageSwitchSensitivity) {
context.router.navigate(const HomeRoute());
setState(() {
_collapse = false;
});
} else {
if (context.read<HomePageState>().showScrollMessage) {
context.read<HomePageState>().showScrollMessage = false;
}
}
}
}
return true;
},
child: ClipRect(child: HomeContent(
collapse: _collapse,
)),
),
],
),
),
),
),
),
),
);
}
}

View File

@ -2,13 +2,21 @@ import 'package:flutter/material.dart';
class HomePageState extends ChangeNotifier {
bool _showScrollMessage = false;
bool _collapse = false;
bool get showScrollMessage {
return _showScrollMessage;
bool get showScrollMessage { return _showScrollMessage; }
set showScrollMessage(bool value) {
if (value != _showScrollMessage) {
_showScrollMessage = value;
notifyListeners();
}
}
set showScrollMessage(bool value) {
_showScrollMessage = value;
notifyListeners();
bool get collapse { return _collapse; }
set collapse(bool value) {
if (value != _collapse) {
_collapse = value;
notifyListeners();
}
}
}

View File

@ -29,6 +29,7 @@ class _RestaurantsListState extends State<RestaurantsList> {
itemCount: restaurants.length,
cacheExtent: 10000,
scrollDirection: Axis.horizontal,
physics: const BouncingScrollPhysics(),
prototypeItem: Padding(
padding: const EdgeInsets.only(right: 15),
child: RestaurantCard(restaurant: restaurants.first),