This article mainly introduces the use of Flutter to listen to the scroll events of the scroll control and some scroll controllers. Finally, it realizes the appBar scroll gradient. If there is anything improper, please correct it.

It takes about 5 minutes to read this article

introduce

The scrolllistener in Flutter can be implemented in two ways, namely, ScrollController and NotificationListener.

ScrollController introduction

ScrollController

ScrollController properties and methods

  • offset: Current scroll position of the scrollable component.
  • jumpTo(double offset)Jump to the specified location,offsetIs the rolling offset.
  • animateTo(double offset,@required Duration duration,@required Curve curve)jumpTo(double offset)It’s the same, but it’s differentanimateToA jump executes an animation, passing in the time required to execute the animation and the animation curve.

ScrollPosition

ScrollPosition is used to save the ScrollPosition of a scrollable component. A ScrollController object may be used by multiple scrollable components,

The ScrollController creates a ScrollPosition object for each scroll component to store location information. ScrollPosition is stored in the Positions property of the ScrollController, which is an array of List

, The only thing that actually holds the location information in the ScrollController is the ScrollPosition, and offset is just a handy property. If you look at the source code, you can see that the offset is obtained from the ScrollPosition.

  /// Returns the attached [ScrollPosition], from which the actual scroll offset
  /// of the [ScrollView] can be obtained.
  /// Calling this is only valid when only a single position is attached.
  ScrollPosition get position {
    assert(_positions.isNotEmpty, 'ScrollController not attached to any scroll views.');
    assert(_positions.length == 1.'ScrollController attached to multiple scroll views.');
    return _positions.single;
  } 

  /// The current scroll offset of the scrollable widget.
  /// Requires the controller to be controlling exactly one scrollable widget.
  double get offset => position.pixels;
Copy the code

Although a ScrollController can correspond to multiple scrollable components, reading the scroll position offset requires one to one reading. In the one-to-many case, we can use other methods to implement the read scroll position. Assuming that a ScrollController now corresponds to two scrollable components, we can obtain the ScrollPosition via position.elementat (index) to obtain the offset:

controller.positions.elementAt(0).pixels
controller.positions.elementAt(1).pixels
Copy the code

The method of ScrollPosition

ScrollPosition has two common methods: These are the animateTo() and jumpTo() methods that actually control the jumpTo the ScrollPosition, and inside the ScrollController both of these methods will end up calling ScrollPosition.

  Future<void> animateTo(
    double offset, {
    @required Duration duration,
    @required Curve curve,
  }) {
    assert(_positions.isNotEmpty, 'ScrollController not attached to any scroll views.');
    final List<Future<void>> animations = List<Future<void>>(_positions.length);
    for (int i = 0; i < _positions.length; i += 1)
      // Call the animateTo method in ScrollPosition
      animations[i] = _positions[i].animateTo(offset, duration: duration, curve: curve);
    return Future.wait<void>(animations).then<void> ((List<void> _) = >null);
  }
Copy the code

ScrollController control principle

ScrollController has three other methods that are important:

  1. createScrollPosition: whenScrollControllerWhen associated with a scrollable component, the scrollable component is first tunedScrollControllercreateScrollPositionMethod to create oneScrollPositionTo store scrolling position information.
ScrollPosition createScrollPosition(
    ScrollPhysics physics,
    ScrollContext context,
    ScrollPosition oldPosition);
Copy the code
  1. Call in the scroll componentcreateScrollPositionMethod is then calledattachMethod to create the number ofScrollPositionAdd information topositionsProperty, this step is called “register location” and only after registrationanimateTo()jumpTo()Can be called.
void attach(ScrollPosition position);
Copy the code
  1. Is finally called when the scrollable component is destroyeddetach()Method, take itScrollPositionObjects fromScrollControllerpositionsProperty, this step is called “logout location”, after logoutanimateTo()jumpTo()Will no longer be called.
void detach(ScrollPosition position);
Copy the code

NotificationListener introduction

Notice the bubbling

The Widget of the Flutter Widget tree can communicate with the parent Widget (including the parent Widget) by sending notifications. The parent component can listen for notifications of interest through a NotificationListener component. This mode of communication is similar to the event bubbling of browsers in Web development. The term “bubbling” is used in Flutter, called notification bubbling

Notification bubbles are similar to user touch event bubbles, with one difference: notification bubbles can be aborted, but user touch events cannot.

Scroll to inform

Notifications are used in many places in Flutter. For example, a Scrollable Widget sends a ScrollNotification when it slides. The Scrollbar determines the position of the Scrollbar by listening to the ScrollNotification.

switch (notification.runtimeType){
  case ScrollStartNotification: print("Start rolling"); break;
  case ScrollUpdateNotification: print("Rolling"); break;
  case ScrollEndNotification: print("Roll stop"); break;
  case OverscrollNotification: print("Scroll to the boundary"); break;
}
Copy the code

ScrollStartNotification and ScrollUpdateNotification inherit ScrollNotification class, and different notification subclasses will contain different information. ScrollUpdateNotification has a scrollDelta property, which records the displacement of the move.

NotificationListener inherits the StatelessWidget class, which can be placed directly in the number of widgets. The template parameter type must be inherited from Notification. When template parameters can be explicitly specified, such as Notification type is scrollend Notification:

NotificationListener<ScrollEndNotification>
Copy the code

NotificationListener will only receive notifications of this parameter type.

The onNotification callback handles the callback for the notification. Its return value is Boolean (bool). When the return value is true, it prevents bubbling and the parent Widget will no longer receive the notification. Continue to bubble up notification when the return value is false.

The difference between

First of all, both methods can implement listening for scrolling, but there are some differences between them:

  1. ScrollControllerCan control the scroll control of the scroll, andNotificationListenerNo.
  2. throughNotificationListenerCan listen anywhere from the scrollable component to the root of the widget, whileScrollControllerThis can only be done if it is associated with a specific scrollable component.
  3. Different information is obtained after receiving a rolling event;NotificationListenerWhen a scroll event is received, the notification carries some information about the current scroll position and ViewPort, andScrollControllerYou can only get the current scroll position.

ScrollController instance

rendering

Code implementation steps

  1. The Scaffold body contains a Stack widget that houses a ListView and a custom appBar. FloatingActionButton places a float button that returns to the top.

    Scaffold(
          body: Stack(
            children: <Widget>[
              MediaQuery.removePadding(
                removeTop: true,
                context: context,
                child: ListView.builder(
                  // ScrollController associates the scroll component
                  controller: _controller,
                  itemCount: 100,
                  itemBuilder: (context, index) {
                    if (index == 0) {
                      return Container(
                        height: 200,
                        child: Swiper(
                          itemBuilder: (BuildContext context, int index) {
                            return new Image.network(
                              "http://via.placeholder.com/350x150",
                              fit: BoxFit.fill,
                            );
                          },
                          itemCount: 3,
                          autoplay: true,
                          pagination: new SwiperPagination(),
                        ),
                      );
                    }
                    return ListTile(
                      title: Text("ListTile:$index")); }, ), ), Opacity( opacity: toolbarOpacity, child: Container( height:98,
                  color: Colors.blue,
                  child: Padding(
                    padding: const EdgeInsets.only(top: 30.0),
                    child: Center(
                      child: Text(
                        "ScrollerDemo",
                        style: TextStyle(color: Colors.white, fontSize: 20.0), ), ), ), ), ) ], ), floatingActionButton: ! showToTopBtn ?null
              : FloatingActionButton(
                  child: Icon(Icons.keyboard_arrow_up),
                  onPressed: () {
                    _controller.animateTo(0.0, duration: Duration(milliseconds: 500), curve: Curves.ease); },),)Copy the code
  2. Create a ScrollController object, add a scrolllistener to the initialization, and associate it with the scrollable widget ListView:

ScrollController _controller = new ScrollController();

@override
void initState() {
  _controller.addListener(() {
    print(_controller.offset); // Prints the scroll position})}Copy the code
  1. Add the relevant business code to _controller.addListener to calculate the transparency according to the scroll offset and implement the appBar scroll gradient:
  double t = _controller.offset / DEFAULT_SCROLLER;
  if (t < 0.0) {
    t = 0.0;
  } else if (t > 1.0) {
    t = 1.0;
  }
  setState(() {
    toolbarOpacity = t;
  });
Copy the code
  1. Check whether floatingActionButton needs to be displayed by specifying the float height and the actual state of floatingActionButton:

    if(_controller.offset < DEFAULT_SHOW_TOP_BTN && showToTopBtn){
      setState(() {
      showToTopBtn = false;
    	});
    }else if(_controller.offset >= DEFAULT_SHOW_TOP_BTN && ! showToTopBtn){ setState(() { showToTopBtn =true;
      });
    }
    Copy the code
  2. Click floatingActionButton to return to the top:

 _controller.animateTo(0.0, duration: Duration(milliseconds: 500), curve: Curves.ease);
Copy the code

Refer to the /demo/scroller_demo.dart file in the GitHub project below for the complete code.

NotificationListener instance

rendering

Code implementation steps

The layout of a NotificationListener instance is basically the same as that of a ScrollController, except that the ListView needs to be wrapped in a NotificationListener as a Child, NotificationListener then determines the roll offset in onNotification:

if (notification is ScrollUpdateNotification && notification.depth == 0) {
  double t = notification.metrics.pixels / DEFAULT_SCROLLER;
  if (t < 0.0) {
    t = 0.0;
  } else if (t > 1.0) {
    t = 1.0;
  }
  setState(() {
    toolbarOpacity = t;
  });

  print(notification.metrics.pixels); // Prints the scroll position
}
Copy the code

Refer to the /demo/ Notification_listener_demo.dart file in the GitHub project below for the complete code

At the end

Complete code to GitHub address: fluter_demo, welcome star and fork.

Here, this article is over, if there is improper place please correct, study together to discuss, thank 🙏.