Implementation of fluent rolling monitoring and actual combat AppBar rolling gradient

introduce

Scrolling monitoring in fluent can generally be implemented in two ways: scrollcontroller and notificationlister.

Introduction to scrollcontroller

ScrollController

Introduce the common properties and methods of scrollcontroller:

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 location information. Scrollposition is stored in the positions attribute of scrollcontroller. It is a list < scrollposition > array. Scrollposition is the real location information in scrollcontroller, and offset is just a convenient attribute. Looking at the source code, we can find that the offset is obtained from 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;

Although a scrollcontroller can correspond to multiple scrollable components, one-to-one reading is required to read the scroll position offset. In the case of one to many, we can use other methods to read the scroll position. Assuming that a scrollcontroller now corresponds to two scrollable components, you can obtain the scrollposition through position.elementat (index) to obtain the offset:

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

Scrollposition method

There are two common methods for scrollposition: animateto () and jumpto (). They are the methods that really control the jump to the scroll position. In the scrollcontroller, the two methods with the same name will eventually call 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)
   // 调用 ScrollPosition 中的 animateTo 方法
   animations[i] = _positions[i].animateTo(offset,duration: duration,curve: curve);
  return Future.wait<void>(animations).then<void>((List<void> _) => null);
 }

Scrollcontroller control principle

Scrollcontroller has three other important methods:

1. Createcrossposition: when the scrollcontroller is associated with a scrollable component, the scrollable component will first call the createcrossposition method of the scrollcontroller to create a scrollposition to store the scrollposition information.

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

2. After the scrolling component calls the createcrossposition method, it will then call the attach method to add the scrollposition information of the creation number to the positions attribute. This step is called "registration location". Animateto() and jumpto() can be called only after registration.

void attach(ScrollPosition position);

3. Finally, when the scrollable component is destroyed, the detach () method will be called to remove its scrollposition object from the positions attribute of the scrollcontroller. This step is called "logout location". Animateto() and jumpto() cannot be called after logout.

void detach(ScrollPosition position);

Notificationlistener introduction

Notification bubble

The child widget in the fluent widget tree can communicate with the parent (including ancestors) widget by sending a notification. The parent component can listen to the notifications it pays attention to through the notificationlistener component. This communication method is similar to the event bubbling of the browser in web development. The term "bubbling" is used in fluent, which is called notification bubbling

Notification bubbling is similar to user touch event bubbling, but there is one difference: notification bubbling can be aborted, but user touch event cannot.

Rolling notification

Notifications are used in many places in fluent. For example, scrollnotification is distributed when scrollable widget slides, and scrollbar determines the position of scroll bar by listening to scrollnotification.

switch (notification.runtimeType){
 case ScrollStartNotification: print("开始滚动"); break;
 case ScrollUpdateNotification: print("正在滚动"); break;
 case ScrollEndNotification: print("滚动停止"); break;
 case OverscrollNotification: print("滚动到边界"); break;
}

Among them, scrollstartnotification and scrollupdatenotification inherit the scrollnotification class. Different types of notification subclasses will contain different information. Scrollupdatenotification has a scrolldelta attribute, which records the displacement of the movement.

Notificationlistener inherits the amount of statelesswidget class. We can directly place it in the number of widgets. We can specify a template parameter through onnotification inside. The template parameter type must inherit from notification. When template parameters can be explicitly specified, for example, the type of notification is rolling end notification:

NotificationListener<ScrollEndNotification>

At this time, the notificationlistener will only receive notifications of this parameter type.

Onnotification callback is a notification processing callback. Its return value is Boolean. When the return value is true, bubbles are prevented, and its parent widget will never receive the notification again; When the return value is false, continue to bubble up notification.

The difference between the two

First of all, these two methods can monitor scrolling, but they still have some differences:

Code implementation steps

Create the interface required for scrolling, a scaffold component, a stack stacked widget in the body, a listview and a user-defined AppBar; Floatingactionbutton places a floating button that returns to the top.

Scaffold(
   body: Stack(
    children: <Widget>[
     MediaQuery.removePadding(
      removeTop: true,context: context,child: ListView.builder(
       // ScrollController 关联滚动组件
       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: @R_834_2419@Fit.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);
       },)

Create a scrollcontroller object, add listening to scrolling in initialization, and associate it with the scrollable widget listview:

 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_ Add relevant business codes to controller.addlistener, calculate the transparency according to the scrolling offset, and realize the scrolling gradient of AppBar:

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

Determine whether the floatingactionbutton needs to be displayed with more scrolling height and the current realistic state of the floatingactionbutton:

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

Click floatingactionbutton to return to the top:

 _controller.animateTo(0.0,curve: Curves.ease);

For the complete code, please refer to / demo / scroller in GitHub project below_ Demo.dart file.

Notificationlistener 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 determines the scroll 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); //打印滚动位置
}

For the complete code, please refer to / demo / notification in the GitHub project below_ listener_ Demo.dart file

The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>