Implementation of flutter rolling monitoring and practical AppBar rolling gradual change

Time:2020-8-10

introduce

Generally, there are two ways to implement rolling monitoring in flutterScrollControllerandNotificationListenerThese two ways.

Introduction to scrollcontroller

ScrollController

Introduce to youScrollControllerCommon attributes and methods:

  • offset: the current scrolling position of the scrollable component.
  • jumpTo(double offset)Jump to the specified location,offsetIs the roll offset.
  • animateTo(double offset,@required Duration duration,@required Curve curve)withjumpTo(double offset)The same, the difference isanimateToWhen jumping, an animation will be executed, and the time and animation curve needed to execute the animation need to be passed in.

ScrollPosition

Scrollposition is used to save the scrolling position of scrollable components. A scrollcontroller object may be used by multiple scrollable components,

The scrollcontroller creates a scrollposition object for each scrolling component to store the location information. What is stored in the scrollposition is in the positions property of the scrollcontroller. It is aList<ScrollPosition>Array, in the scrollcontroller, it is scrollposition that really saves the location information, while offset is just a convenient property. Looking at the source code, we can find 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;

OneScrollControllerAlthough it can correspond to multiple scrollable components, the scrolling position is readoffset, a one-to-one read is required. In the case of one to many, we can use other methods to read the scroll position. Suppose there’s one nowScrollControllerCorresponding to two components that can be scrolled, theposition.elementAt(index)To getScrollPositionIn order to obtainoffset


controller.positions.elementAt(0).pixels
controller.positions.elementAt(1).pixels

The method of scrollposition

ScrollPositionThere are two common methods: they areanimateTo()andjumpTo()They are the real method to control the jump to the scrolling position. In the scrollcontroller, these two methods with the same name will eventually call the scrollposition methods.

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);
 }

Control principle of scrollcontroller

ScrollControllerThere are three other important methods

1、createScrollPosition: whenScrollControllerWhen associated with a scrollable component, the scrollable component first adjusts theScrollControllerOfcreateScrollPositionMethod to create aScrollPositionTo store scroll position information.


ScrollPosition createScrollPosition(
  ScrollPhysics physics,
  ScrollContext context,
  ScrollPosition oldPosition);

2. In the scrolling component callcreateScrollPositionMethod is calledattachMethod to create theScrollPositionInformation added topositionsProperty, this step is called “register location”, only after registrationanimateTo()andjumpTo()Can be called.


void attach(ScrollPosition position);

3. Finally, when the scrollable component is destroyed, thedetach()Method, theScrollPositionObject fromScrollControllerOfpositionsAttribute, this step is called “logout location”, after logoutanimateTo()andjumpTo()Will no longer be called.


void detach(ScrollPosition position);

Introduction to notificationlister

Notice bubble

The child widget in the filter widget tree can communicate with the parent (including the ancestor) widget by sending a notification, and the parent component can use theNotificationListenerComponent is used to listen for the notice of concern. This communication method is similar to the event bubble of browser in web development. In fluent, the term “bubble” is used, which is called “bubble”Notice bubble

Notification bubbles are similar to user touch event bubbles, but with one difference: notification bubbles can stop, but user touch events do not.

Rolling notification

Notification is used in many places in fluent, such as distribution when scrollable widget slidesRolling notification(scrollnotification), andScrollbarIt’s through listeningScrollNotificationTo determine the position of the scroll bar.

switch (notification.runtimeType){
 Case scrollstartnotification: print; break;
 Case scrollupdate notification: print; break;
 Case scrollendnotification: print; break;
 Case overscrollnotification: print; break;
}

amongScrollStartNotificationandScrollUpdateNotificationIt’s all inheritanceScrollNotificationClass. Different types of notification subclasses contain different information,ScrollUpdateNotificationThere is onescrollDeltaProperty, which records the displacement of the movement.

NotificationListenerTime inheritanceStatelessWidgetClass, we can directly place it in the widget number through theonNotificationYou can specify a template parameter whose type must be inherited fromNotificationWhen the template parameters can be specified explicitly, for example, if the type of notification is rolling end notification:


NotificationListener<ScrollEndNotification>

This is the timeNotificationListenerOnly the notification of the parameter type will be received.

onNotificationThe callback is a notification processing callback. Its return value is Boolean. When the return value istrueWhen bubble is prevented, the parent widget will no longer receive the notification; when the return value isfalseContinue to bubble up notification.

The difference between the two

First of all, these two methods can monitor scrolling, but there are some differences between them

  • ScrollControllerYou can control the scrolling of the scroll control, andNotificationListenerIt can’t be.
  • adoptNotificationListenerYou can listen anywhere from the scrollable component to the root of the widget tree, andScrollControllerCan only be associated with a specific scrollable component.
  • The information obtained after receiving the rolling event is different;NotificationListenerWhen a scrolling event is received, the notification carries some information about the current scrolling position and the viewport, andScrollControllerOnly the current scroll position can be obtained. Effect picture of scrollcontroller instance

Code implementation steps

Create the required interface for scrolling, aScaffoldassemblybodyThere is a way insideStackA stack of widgets with alistview, and customappBarfloatingActionButtonPlace a hover button back to the top.

Scaffold(
   body: Stack(
    children: <Widget>[
     MediaQuery.removePadding(
      removeTop: true,
      context: context,
      child: ListView.builder(
       //Scrollcontroller is associated with scrolling components
       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);
       },
      ),
  )

establishScrollControllerObject, add a monitor for scrolling in initialization, andListViewThis scrollable widget is associated with:


 double t = _controller.offset / DEFAULT_SCROLLER;
 if (t < 0.0) {
  t = 0.0;
 } else if (t > 1.0) {
  t = 1.0;
 }
 setState(() {
  toolbarOpacity = t;
 });

In_ controller.addListener Add the relevant business code in, calculate the transparency according to the rolling offset, and realize the app bar rolling gradient


if(_controller.offset < DEFAULT_SHOW_TOP_BTN && showToTopBtn){
 setState(() {
 showToTopBtn = false;
	});
}else if(_controller.offset >= DEFAULT_SHOW_TOP_BTN && !showToTopBtn){
 setState(() {
  showToTopBtn = true;
 });
}

More scrolling height and currentfloatingActionButtonThe reality of the state, judgmentfloatingActionButtonNeed to show:


if(_controller.offset < DEFAULT_SHOW_TOP_BTN && showToTopBtn){
 setState(() {
 showToTopBtn = false;
	});
}else if(_controller.offset >= DEFAULT_SHOW_TOP_BTN && !showToTopBtn){
 setState(() {
  showToTopBtn = true;
 });
}

clickfloatingActionButtonBack to top:


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

Please refer to the full code of hub/demo/scroller_demo.dartDocuments.

Notificationlister instance

design sketch

Code implementation steps

In the notificationlister instance, the layout is basically the same as that of the scrollcontroller. The difference is that the listview needs to be wrapped in the notificationlister as a child, and then the notificationlister judges the rolling 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 ); // print scroll position
}

Please refer to the full code of hub/demo/notification_listener_demo.dartfile

The above is the whole content of this article, I hope to help you in your study, and I hope you can support developeppaer more.