mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

<!-- Thanks for filing a pull request! Reviewers are typically assigned within a week of filing a request. To learn more about code review, see our documentation on Tree Hygiene: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md --> This PR removes redundant useMaterial3: true as described in https://github.com/flutter/flutter/issues/162818 *List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.* - https://github.com/flutter/flutter/issues/162818 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --------- Co-authored-by: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com>
154 lines
5.1 KiB
Dart
154 lines
5.1 KiB
Dart
// Copyright 2014 The Flutter Authors. 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';
|
|
|
|
/// Flutter code sample for [ScrollController] & [ScrollNotification].
|
|
|
|
void main() => runApp(const ScrollNotificationDemo());
|
|
|
|
class ScrollNotificationDemo extends StatefulWidget {
|
|
const ScrollNotificationDemo({super.key});
|
|
|
|
@override
|
|
State<ScrollNotificationDemo> createState() => _ScrollNotificationDemoState();
|
|
}
|
|
|
|
class _ScrollNotificationDemoState extends State<ScrollNotificationDemo> {
|
|
ScrollNotification? _lastNotification;
|
|
late final ScrollController _controller;
|
|
bool _useController = true;
|
|
|
|
// This method handles the notification from the ScrollController.
|
|
void _handleControllerNotification() {
|
|
print('Notified through the scroll controller.');
|
|
// Access the position directly through the controller for details on the
|
|
// scroll position.
|
|
}
|
|
|
|
// This method handles the notification from the NotificationListener.
|
|
bool _handleScrollNotification(ScrollNotification notification) {
|
|
print('Notified through scroll notification.');
|
|
// The position can still be accessed through the scroll controller, but
|
|
// the notification object provides more details about the activity that is
|
|
// occurring.
|
|
if (_lastNotification.runtimeType != notification.runtimeType) {
|
|
setState(() {
|
|
// Call set state to respond to a change in the scroll notification.
|
|
_lastNotification = notification;
|
|
});
|
|
}
|
|
|
|
// Returning false allows the notification to continue bubbling up to
|
|
// ancestor listeners. If we wanted the notification to stop bubbling,
|
|
// return true.
|
|
return false;
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
_controller = ScrollController();
|
|
if (_useController) {
|
|
// When listening to scrolling via the ScrollController, call
|
|
// `addListener` on the controller.
|
|
_controller.addListener(_handleControllerNotification);
|
|
}
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
// ListView.separated works very similarly to this example with
|
|
// CustomScrollView & SliverList.
|
|
Widget body = CustomScrollView(
|
|
// Provide the scroll controller to the scroll view.
|
|
controller: _controller,
|
|
slivers: <Widget>[
|
|
SliverList.separated(
|
|
itemCount: 50,
|
|
itemBuilder: (_, int index) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 20.0),
|
|
child: Text('Item $index'),
|
|
);
|
|
},
|
|
separatorBuilder: (_, _) => const Divider(indent: 20, endIndent: 20, thickness: 2),
|
|
),
|
|
],
|
|
);
|
|
|
|
if (!_useController) {
|
|
// If we are not using a ScrollController to listen to scrolling,
|
|
// let's use a NotificationListener. Similar, but with a different
|
|
// handler that provides information on what scrolling is occurring.
|
|
body = NotificationListener<ScrollNotification>(
|
|
onNotification: _handleScrollNotification,
|
|
child: body,
|
|
);
|
|
}
|
|
|
|
return MaterialApp(
|
|
theme: ThemeData.from(colorScheme: ColorScheme.fromSeed(seedColor: Colors.blueGrey)),
|
|
home: Scaffold(
|
|
appBar: AppBar(
|
|
title: const Text('Listening to a ScrollPosition'),
|
|
bottom: PreferredSize(
|
|
preferredSize: const Size.fromHeight(70),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: <Widget>[
|
|
if (!_useController) Text('Last notification: ${_lastNotification.runtimeType}'),
|
|
if (!_useController) const SizedBox.square(dimension: 10),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: <Widget>[
|
|
const Text('with:'),
|
|
Radio<bool>(
|
|
value: true,
|
|
groupValue: _useController,
|
|
onChanged: _handleRadioChange,
|
|
),
|
|
const Text('ScrollController'),
|
|
Radio<bool>(
|
|
value: false,
|
|
groupValue: _useController,
|
|
onChanged: _handleRadioChange,
|
|
),
|
|
const Text('NotificationListener'),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
body: body,
|
|
),
|
|
);
|
|
}
|
|
|
|
void _handleRadioChange(bool? value) {
|
|
if (value == null) {
|
|
return;
|
|
}
|
|
if (value != _useController) {
|
|
setState(() {
|
|
// Respond to a change in selected radio button, and add/remove the
|
|
// listener to the scroll controller.
|
|
_useController = value;
|
|
if (_useController) {
|
|
_controller.addListener(_handleControllerNotification);
|
|
} else {
|
|
_controller.removeListener(_handleControllerNotification);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.removeListener(_handleControllerNotification);
|
|
super.dispose();
|
|
}
|
|
}
|