Skip to content

Instantly share code, notes, and snippets.

@sirpengi
Created July 19, 2023 17:08
Show Gist options
  • Save sirpengi/eb123203f1d5bdc0bb9ed50f6d37f38f to your computer and use it in GitHub Desktop.
Save sirpengi/eb123203f1d5bdc0bb9ed50f6d37f38f to your computer and use it in GitHub Desktop.
Flutter scroll testing
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final ScrollController scrollEndController = ScrollController();
final ValueNotifier<bool> scrollEndValue = ValueNotifier<bool>(false);
final ScrollController addListenerController = ScrollController();
final ValueNotifier<bool> addListenerValue = ValueNotifier<bool>(false);
final ScrollController scrollMetricsController = ScrollController();
final ValueNotifier<bool> scrollMetricsValue = ValueNotifier<bool>(false);
void onAddListenerChange() {
final position = addListenerController.position;
if (position.extentAfter == 0) {
addListenerValue.value = false;
} else {
addListenerValue.value = true;
}
}
@override
Widget build(BuildContext context) {
addListenerController.addListener(onAddListenerChange);
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Row(
children: <Widget>[
NotificationListener<ScrollEndNotification>(
onNotification: (scrollEnd) {
final metrics = scrollEnd.metrics;
if (metrics.extentAfter == 0) {
scrollEndValue.value = false;
} else {
scrollEndValue.value = true;
}
return true;
},
child: MyScrollable(color: Colors.red, controller: scrollEndController, notifier: scrollEndValue),
),
MyScrollable(color: Colors.green, controller: addListenerController, notifier: addListenerValue),
NotificationListener<ScrollMetricsNotification>(
onNotification: (scrollMetrics) {
final metrics = scrollMetrics.metrics;
if (metrics.extentAfter == 0) {
scrollMetricsValue.value = false;
} else {
scrollMetricsValue.value = true;
}
return true;
},
child: MyScrollable(color: Colors.blue, controller: scrollMetricsController, notifier: scrollMetricsValue),
),
])
);
}
}
class MyScrollable extends StatelessWidget {
const MyScrollable({super.key, required this.color, required this.controller, required this.notifier});
final Color color;
final ScrollController controller;
final ValueNotifier<bool> notifier;
@override
Widget build(BuildContext context) {
return Stack(
children: [
SingleChildScrollView(
controller: controller,
child: Container(width: 100, height: 400, color: color),
),
Positioned(
bottom: 0,
right: 0,
child: ScrollToBottomButton(controller: controller, notifier: notifier)
)]);
}
}
class ScrollToBottomButton extends StatelessWidget {
const ScrollToBottomButton({super.key, required this.controller, required this.notifier});
final ValueNotifier<bool> notifier;
final ScrollController controller;
Future<void> _navigateToBottom(BuildContext context) async {
controller.animateTo(0, duration: const Duration(milliseconds: 300), curve: Curves.easeIn);
}
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<bool>(
builder: (BuildContext context, bool value, Widget? child) {
return (value && child != null) ? child : const SizedBox.shrink();
},
valueListenable: notifier,
child: TextButton(
child: const Text("Go", style: TextStyle(color: Colors.black)),
onPressed: () => _navigateToBottom(context)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment