最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Flutter 滾動(dòng)監(jiān)聽(tīng)及實(shí)戰(zhàn)appBar滾動(dòng)漸變的實(shí)現(xiàn)

 更新時(shí)間:2019年09月29日 10:49:36   作者:曉峰殘?jiān)? 
這篇文章主要介紹了Flutter 滾動(dòng)監(jiān)聽(tīng)及實(shí)戰(zhàn)appBar滾動(dòng)漸變,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

介紹

在 Flutter 中滾動(dòng)監(jiān)聽(tīng)一般可以采用兩種方式來(lái)實(shí)現(xiàn),分別是ScrollControllerNotificationListener這兩種方式。

ScrollController介紹

ScrollController

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

  • offset:可滾動(dòng)組件當(dāng)前的滾動(dòng)位置。
  • jumpTo(double offset)跳轉(zhuǎn)到指定位置,offset為滾動(dòng)偏移量。
  • animateTo(double offset,@required Duration duration,@required Curve curve)jumpTo(double offset)一樣,不同的是animateTo跳轉(zhuǎn)時(shí)會(huì)執(zhí)行一個(gè)動(dòng)畫(huà),需要傳入執(zhí)行動(dòng)畫(huà)需要的時(shí)間和動(dòng)畫(huà)曲線。

ScrollPosition

ScrollPosition是用來(lái)保存可滾動(dòng)組件的滾動(dòng)位置的。一個(gè) ScrollController 對(duì)象可能會(huì)被多個(gè)可滾動(dòng)的組件使用,

ScrollController 會(huì)為每一個(gè)滾動(dòng)組件創(chuàng)建一個(gè) ScrollPosition 對(duì)象來(lái)存儲(chǔ)位置信息。ScrollPosition 中存儲(chǔ)的是在 ScrollController 的 positions 屬性里面,他是一個(gè)List<ScrollPosition>數(shù)組,在 ScrollController 中真正保存位置信息的就是 ScrollPosition,而 offset 只是一個(gè)便捷使用的屬性。查看源碼中可以發(fā)現(xiàn) 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;

一個(gè)ScrollController雖然可以對(duì)應(yīng)多個(gè)可滾動(dòng)組件,但是讀取滾動(dòng)位置offset,則需要一對(duì)一讀取。在一對(duì)多的情況下,我們可以使用其他方法來(lái)實(shí)現(xiàn)讀取滾動(dòng)位置。假設(shè)現(xiàn)在一個(gè)ScrollController對(duì)應(yīng)了兩個(gè)可以滾動(dòng)的組件,那么可以通過(guò)position.elementAt(index)來(lái)獲取ScrollPosition,從而獲得offset

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

ScrollPosition的方法

ScrollPosition有兩個(gè)常用方法:分別是animateTo()jumpTo(),他們才是真正控制跳轉(zhuǎn)到滾動(dòng)位置的方法,在 ScrollController 中這兩個(gè)同名方法,內(nèi)部最終都會(huì)調(diào)用 ScrollPosition 這兩個(gè)方法。

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)
   // 調(diào)用 ScrollPosition 中的 animateTo 方法
   animations[i] = _positions[i].animateTo(offset, duration: duration, curve: curve);
  return Future.wait<void>(animations).then<void>((List<void> _) => null);
 }

ScrollController控制原理

ScrollController還有其他比較重要的三個(gè)方法:

1、createScrollPosition:當(dāng)ScrollController和可滾動(dòng)組件關(guān)聯(lián)時(shí),可滾動(dòng)組件首先會(huì)調(diào)ScrollControllercreateScrollPosition方法來(lái)創(chuàng)建一個(gè)ScrollPosition來(lái)存儲(chǔ)滾動(dòng)位置信息。

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

2、在滾動(dòng)組件調(diào)用createScrollPosition方法之后,接著會(huì)調(diào)用attach方法來(lái)將創(chuàng)建號(hào)的ScrollPosition信息添加到positions屬性中,這一步稱為“注冊(cè)位置”,只有注冊(cè)后animateTo()jumpTo()才可以被調(diào)用。

void attach(ScrollPosition position);

3、最后當(dāng)可滾動(dòng)組件被銷(xiāo)毀時(shí),會(huì)調(diào)用detach()方法,將其ScrollPosition對(duì)象從ScrollControllerpositions屬性中移除,這一步稱為“注銷(xiāo)位置”,注銷(xiāo)后animateTo()jumpTo()將不能再被調(diào)用。

void detach(ScrollPosition position);

NotificationListener介紹

通知冒泡

Flutter Widget 樹(shù)中子 Widge t可以通過(guò)發(fā)送通知(Notification)與父(包括祖先) Widget 進(jìn)行通信,父級(jí)組件可以通過(guò)NotificationListener組件來(lái)監(jiān)聽(tīng)自己關(guān)注的通知,這種通信方式類(lèi)似于 Web 開(kāi)發(fā)中瀏覽器的事件冒泡,在 Flutter 中就沿用了“冒泡”這個(gè)術(shù)語(yǔ),稱為通知冒泡

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

滾動(dòng)通知

Flutter 中很多地方使用了通知,如可滾動(dòng)組件(Scrollable Widget)滑動(dòng)時(shí)就會(huì)分發(fā)滾動(dòng)通知(ScrollNotification),而Scrollbar正是通過(guò)監(jiān)聽(tīng)ScrollNotification來(lái)確定滾動(dòng)條位置的。

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

其中ScrollStartNotificationScrollUpdateNotification等都是繼承ScrollNotification類(lèi)的,不同類(lèi)型的通知子類(lèi)會(huì)包含不同的信息,ScrollUpdateNotification有一個(gè)scrollDelta屬性,它記錄了移動(dòng)的位移。

NotificationListener時(shí)繼承StatelessWidget類(lèi)的額,左右我們可以直接在放置在Widget 數(shù)中,通過(guò)里面的onNotification可以指定一個(gè)模板參數(shù),該模板參數(shù)類(lèi)型必須是繼承自Notification,可以顯式指定模板參數(shù)時(shí),比如通知的類(lèi)型為滾動(dòng)結(jié)束通知:

NotificationListener<ScrollEndNotification>

這個(gè)時(shí)候NotificationListener便只會(huì)接收該參數(shù)類(lèi)型的通知。

onNotification回調(diào)為通知處理回調(diào),他的返回值時(shí)布爾類(lèi)型(bool),當(dāng)返回值為true時(shí),阻止冒泡,其父級(jí) Widget 將再也收不到該通知;當(dāng)返回值為false時(shí)繼續(xù)向上冒泡通知。

兩者區(qū)別

首先這兩種方式都可以實(shí)現(xiàn)對(duì)滾動(dòng)的監(jiān)聽(tīng),但是他們還是有一些區(qū)別:

  • ScrollController可以控制滾動(dòng)控件的滾動(dòng),而NotificationListener是不可以的。
  • 通過(guò)NotificationListener可以在從可滾動(dòng)組件到widget樹(shù)根之間任意位置都能監(jiān)聽(tīng),而ScrollController只能和具體的可滾動(dòng)組件關(guān)聯(lián)后才可以。
  • 收到滾動(dòng)事件后獲得的信息不同;NotificationListener在收到滾動(dòng)事件時(shí),通知中會(huì)攜帶當(dāng)前滾動(dòng)位置和ViewPort的一些信息,而ScrollController只能獲取當(dāng)前滾動(dòng)位置。ScrollController實(shí)例效果圖

代碼實(shí)現(xiàn)步驟

創(chuàng)建滾動(dòng)所需的界面,一個(gè)Scaffold組件body里面方式一個(gè)Stack的層疊小部件,里面放置一個(gè)listview,和自定義的appBar;floatingActionButton放置一個(gè)返回頂部的懸浮按鈕。

Scaffold(
   body: Stack(
    children: <Widget>[
     MediaQuery.removePadding(
      removeTop: true,
      context: context,
      child: ListView.builder(
       // ScrollController 關(guān)聯(lián)滾動(dòng)組件
       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);
       },
      ),
  )

創(chuàng)建ScrollController對(duì)象,在初始化中添加對(duì)滾動(dòng)的監(jiān)聽(tīng),并和ListView這個(gè)可滾動(dòng)小部件進(jìn)行關(guān)聯(lián):

 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 中添加相關(guān)業(yè)務(wù)代碼,根據(jù)滾動(dòng)的偏移量計(jì)算出透明度,實(shí)現(xiàn)appBar滾動(dòng)漸變:

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

更具滾動(dòng)的高度和當(dāng)前floatingActionButton的現(xiàn)實(shí)狀態(tài),判斷floatingActionButton是否需要展示:

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

點(diǎn)擊floatingActionButton返回到頂部:

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

完整代碼請(qǐng)參考下方GitHub項(xiàng)目中/demo/scroller_demo.dart文件。

NotificationListener實(shí)例

效果圖

代碼實(shí)現(xiàn)步驟

在 NotificationListener 實(shí)例中布局基本上和 ScrollController 一致,不同的地方在于 ListView 需要包裹在 NotificationListener 中作為 child,然后 NotificationListener 在 onNotification 中判斷滾動(dòng)偏移量:

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); //打印滾動(dòng)位置
}

完整代碼請(qǐng)參考下方GitHub項(xiàng)目中/demo/notification_listener_demo.dart文件

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Flutter自動(dòng)路由插件auto_route使用詳解

    Flutter自動(dòng)路由插件auto_route使用詳解

    這篇文章主要為大家介紹了Flutter自動(dòng)路由插件auto_route的基本使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Android 自定義View實(shí)現(xiàn)多節(jié)點(diǎn)進(jìn)度條功能

    Android 自定義View實(shí)現(xiàn)多節(jié)點(diǎn)進(jìn)度條功能

    這篇文章主要介紹了Android 自定義View實(shí)現(xiàn)多節(jié)點(diǎn)進(jìn)度條,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • Android App開(kāi)發(fā)中ViewPager組件的入門(mén)使用教程

    Android App開(kāi)發(fā)中ViewPager組件的入門(mén)使用教程

    這篇文章主要介紹了Android App開(kāi)發(fā)中ViewPager組件的入門(mén)使用教程,ViewPager主要用來(lái)實(shí)現(xiàn)通過(guò)滑動(dòng)來(lái)切換頁(yè)面的效果,需要的朋友可以參考下
    2016-03-03
  • 利用Flutter繪制出3D效果動(dòng)畫(huà)

    利用Flutter繪制出3D效果動(dòng)畫(huà)

    本文主要介紹了Flutter繪圖的Path的應(yīng)用。Flutter的Path類(lèi)提供了一個(gè)三維空間的變換方法,可以實(shí)現(xiàn)路徑在三維空間的平移、旋轉(zhuǎn)等操作,從而可以實(shí)現(xiàn)3D繪制的效果,感興趣的可以了解一下
    2022-08-08
  • Flutter中http請(qǐng)求抓包的完美解決方案

    Flutter中http請(qǐng)求抓包的完美解決方案

    這篇文章主要給大家介紹了關(guān)于Flutter中http請(qǐng)求抓包的完美解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Flutter具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Kotlin?launch原理全面分析

    Kotlin?launch原理全面分析

    在Android開(kāi)發(fā)中,launch是我們經(jīng)常用的,今天來(lái)看看它是什么原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2022-11-11
  • Android Studio中配置OpenCV庫(kù)開(kāi)發(fā)環(huán)境的教程

    Android Studio中配置OpenCV庫(kù)開(kāi)發(fā)環(huán)境的教程

    這篇文章主要介紹了Android Studio中配置OpenCV庫(kù)開(kāi)發(fā)環(huán)境的教程,OpenCV有Java接口,因而也經(jīng)常被用來(lái)做安卓開(kāi)發(fā),需要的朋友可以參考下
    2016-05-05
  • 安卓實(shí)現(xiàn)自定義圓形取色盤(pán)

    安卓實(shí)現(xiàn)自定義圓形取色盤(pán)

    這篇文章主要介紹了安卓實(shí)現(xiàn)自定義圓形取色盤(pán)的相關(guān)資料,并且給出了相應(yīng)的代碼,推薦給大家,需要的朋友可以參考下
    2022-08-08
  • Android Studio中CodeStyle模板的配置方式

    Android Studio中CodeStyle模板的配置方式

    這篇文章主要介紹了Android Studio中CodeStyle模板的配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-03-03
  • Android進(jìn)階教程之ViewGroup自定義布局

    Android進(jìn)階教程之ViewGroup自定義布局

    這篇文章主要給大家介紹了關(guān)于Android進(jìn)階教程之ViewGroup自定義布局的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位Android開(kāi)發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06

最新評(píng)論

体育| 桐庐县| 原平市| 柘荣县| 泰顺县| 韩城市| 杭锦后旗| 磐石市| 浦北县| 望城县| 大悟县| 嘉黎县| 南宫市| 贵州省| 平泉县| 沽源县| 莒南县| 弥勒县| 神木县| 西城区| 舟山市| 丽水市| 内丘县| 安龙县| 平罗县| 盈江县| 桂平市| 杭锦后旗| 乐陵市| 芮城县| 张家界市| 桐柏县| 东安县| 缙云县| 嘉黎县| 安新县| 衡东县| 恩施市| 闽侯县| 温宿县| 鹤壁市|