91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Flutter 滾動監聽及實戰appBar滾動漸變的實現

發布時間:2020-09-30 17:09:54 來源:腳本之家 閱讀:304 作者:曉峰殘月 欄目:移動開發

介紹

在 Flutter 中滾動監聽一般可以采用兩種方式來實現,分別是ScrollControllerNotificationListener這兩種方式。

ScrollController介紹

ScrollController

介紹一下ScrollController常用的屬性和方法:

  • offset:可滾動組件當前的滾動位置。
  • jumpTo(double offset)跳轉到指定位置,offset為滾動偏移量。
  • animateTo(double offset,@required Duration duration,@required Curve curve)jumpTo(double offset)一樣,不同的是animateTo跳轉時會執行一個動畫,需要傳入執行動畫需要的時間和動畫曲線。

ScrollPosition

ScrollPosition是用來保存可滾動組件的滾動位置的。一個 ScrollController 對象可能會被多個可滾動的組件使用,

ScrollController 會為每一個滾動組件創建一個 ScrollPosition 對象來存儲位置信息。ScrollPosition 中存儲的是在 ScrollController 的 positions 屬性里面,他是一個List<ScrollPosition>數組,在 ScrollController 中真正保存位置信息的就是 ScrollPosition,而 offset 只是一個便捷使用的屬性。查看源碼中可以發現 offset 獲取就是從 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;

一個ScrollController雖然可以對應多個可滾動組件,但是讀取滾動位置offset,則需要一對一讀取。在一對多的情況下,我們可以使用其他方法來實現讀取滾動位置。假設現在一個ScrollController對應了兩個可以滾動的組件,那么可以通過position.elementAt(index)來獲取ScrollPosition,從而獲得offset

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

ScrollPosition的方法

ScrollPosition有兩個常用方法:分別是animateTo()jumpTo(),他們才是真正控制跳轉到滾動位置的方法,在 ScrollController 中這兩個同名方法,內部最終都會調用 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控制原理

ScrollController還有其他比較重要的三個方法:

1、createScrollPosition:當ScrollController和可滾動組件關聯時,可滾動組件首先會調ScrollControllercreateScrollPosition方法來創建一個ScrollPosition來存儲滾動位置信息。

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

2、在滾動組件調用createScrollPosition方法之后,接著會調用attach方法來將創建號的ScrollPosition信息添加到positions屬性中,這一步稱為“注冊位置”,只有注冊后animateTo()jumpTo()才可以被調用。

void attach(ScrollPosition position);

3、最后當可滾動組件被銷毀時,會調用detach()方法,將其ScrollPosition對象從ScrollControllerpositions屬性中移除,這一步稱為“注銷位置”,注銷后animateTo()jumpTo()將不能再被調用。

void detach(ScrollPosition position);

NotificationListener介紹

通知冒泡

Flutter Widget 樹中子 Widge t可以通過發送通知(Notification)與父(包括祖先) Widget 進行通信,父級組件可以通過NotificationListener組件來監聽自己關注的通知,這種通信方式類似于 Web 開發中瀏覽器的事件冒泡,在 Flutter 中就沿用了“冒泡”這個術語,稱為通知冒泡

通知冒泡和用戶觸摸事件冒泡是相似的,但有一點不同:通知冒泡可以中止,但用戶觸摸事件不行。

滾動通知

Flutter 中很多地方使用了通知,如可滾動組件(Scrollable Widget)滑動時就會分發滾動通知(ScrollNotification),而Scrollbar正是通過監聽ScrollNotification來確定滾動條位置的。

switch (notification.runtimeType){
 case ScrollStartNotification: print("開始滾動"); break;
 case ScrollUpdateNotification: print("正在滾動"); break;
 case ScrollEndNotification: print("滾動停止"); break;
 case OverscrollNotification: print("滾動到邊界"); break;
}

其中ScrollStartNotificationScrollUpdateNotification等都是繼承ScrollNotification類的,不同類型的通知子類會包含不同的信息,ScrollUpdateNotification有一個scrollDelta屬性,它記錄了移動的位移。

NotificationListener時繼承StatelessWidget類的額,左右我們可以直接在放置在Widget 數中,通過里面的onNotification可以指定一個模板參數,該模板參數類型必須是繼承自Notification,可以顯式指定模板參數時,比如通知的類型為滾動結束通知:

NotificationListener<ScrollEndNotification>

這個時候NotificationListener便只會接收該參數類型的通知。

onNotification回調為通知處理回調,他的返回值時布爾類型(bool),當返回值為true時,阻止冒泡,其父級 Widget 將再也收不到該通知;當返回值為false時繼續向上冒泡通知。

兩者區別

首先這兩種方式都可以實現對滾動的監聽,但是他們還是有一些區別:

  • ScrollController可以控制滾動控件的滾動,而NotificationListener是不可以的。
  • 通過NotificationListener可以在從可滾動組件到widget樹根之間任意位置都能監聽,而ScrollController只能和具體的可滾動組件關聯后才可以。
  • 收到滾動事件后獲得的信息不同;NotificationListener在收到滾動事件時,通知中會攜帶當前滾動位置和ViewPort的一些信息,而ScrollController只能獲取當前滾動位置。ScrollController實例效果圖

Flutter 滾動監聽及實戰appBar滾動漸變的實現

代碼實現步驟

創建滾動所需的界面,一個Scaffold組件body里面方式一個Stack的層疊小部件,里面放置一個listview,和自定義的appBarfloatingActionButton放置一個返回頂部的懸浮按鈕。

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

創建ScrollController對象,在初始化中添加對滾動的監聽,并和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;
 });

在 _controller.addListener 中添加相關業務代碼,根據滾動的偏移量計算出透明度,實現appBar滾動漸變:

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

更具滾動的高度和當前floatingActionButton的現實狀態,判斷floatingActionButton是否需要展示:

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

點擊floatingActionButton返回到頂部:

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

完整代碼請參考下方GitHub項目中/demo/scroller_demo.dart文件。

NotificationListener實例

效果圖

Flutter 滾動監聽及實戰appBar滾動漸變的實現

代碼實現步驟

在 NotificationListener 實例中布局基本上和 ScrollController 一致,不同的地方在于 ListView 需要包裹在 NotificationListener 中作為 child,然后 NotificationListener 在 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); //打印滾動位置
}

完整代碼請參考下方GitHub項目中/demo/notification_listener_demo.dart文件

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宾阳县| 孟村| 谢通门县| 京山县| 潮州市| 娄底市| 抚远县| 西乌| 上杭县| 托克逊县| 泸州市| 隆林| 马鞍山市| 保山市| 乌审旗| 汉川市| 南丹县| 报价| 霍州市| 万安县| 兴宁市| 莎车县| 清水河县| 都昌县| 东光县| 内丘县| 西乌珠穆沁旗| 南投市| 沾益县| 凤凰县| 敦化市| 华容县| 靖江市| 越西县| 东阿县| 贵德县| 舞钢市| 买车| 苏州市| 达拉特旗| 莒南县|