25.Flutter的ListView監(jiān)聽(tīng)滾動(dòng)事件之ScrollController

對(duì)于滾動(dòng)的視圖,我們經(jīng)常需要監(jiān)聽(tīng)它的一些滾動(dòng)事件,在監(jiān)聽(tīng)到的時(shí)候去做對(duì)應(yīng)的一些事情。

比如視圖滾動(dòng)到底部時(shí),我們可能希望做上拉加載更多;

比如滾動(dòng)到一定位置時(shí)顯示一個(gè)回到頂部的按鈕,點(diǎn)擊回到頂部的按鈕,回到頂部;

比如監(jiān)聽(tīng)滾動(dòng)什么時(shí)候開(kāi)始,什么時(shí)候結(jié)束;

在Flutter中監(jiān)聽(tīng)滾動(dòng)相關(guān)的內(nèi)容由兩部分組成:ScrollController和ScrollNotification。



ScrollController

在Flutter中,Widget并不是最終渲染到屏幕上的元素(真正渲染的是RenderObject),因此通常這種監(jiān)聽(tīng)事件以及相關(guān)的信息并不能直接從Widget中獲取,而是必須通過(guò)對(duì)應(yīng)的Widget的Controller來(lái)實(shí)現(xiàn)。


ListView、GridView的組件控制器是ScrollController,我們可以通過(guò)它來(lái)獲取視圖的滾動(dòng)信息,并且可以調(diào)用里面的方法來(lái)更新視圖的滾動(dòng)位置。

另外,通常情況下,我們會(huì)根據(jù)滾動(dòng)的位置來(lái)改變一些Widget的狀態(tài)信息,所以ScrollController通常會(huì)和StatefulWidget一起來(lái)使用,并且會(huì)在其中控制它的初始化、監(jiān)聽(tīng)、銷毀等事件。

我們來(lái)做一個(gè)案例,當(dāng)滾動(dòng)到1000位置的時(shí)候,顯示一個(gè)回到頂部的按鈕:

jumpTo(double offset)、animateTo(double offset,...):這兩個(gè)方法用于跳轉(zhuǎn)到指定的位置,它們不同之處在于,后者在跳轉(zhuǎn)時(shí)會(huì)執(zhí)行一個(gè)動(dòng)畫,而前者不會(huì)。

ScrollController間接繼承自Listenable,我們可以根據(jù)ScrollController來(lái)監(jiān)聽(tīng)滾動(dòng)事件。


classMyHomePageextendsStatefulWidget{

? @override

? State<StatefulWidget> createState() => MyHomePageState();

}

classMyHomePageStateextendsState{

? ScrollController _controller;

? bool _isShowTop = false;


? @override

? void initState() {

? ? // 初始化ScrollController

? ? _controller = ScrollController();


? ? // 監(jiān)聽(tīng)滾動(dòng)

? ? _controller.addListener(() {

? ? ? var tempSsShowTop = _controller.offset >= 1000;

? ? ? if (tempSsShowTop != _isShowTop) {

? ? ? ? setState(() {

? ? ? ? ? _isShowTop = tempSsShowTop;

? ? ? ? });

? ? ? }

? ? });


? ? super.initState();

? }

? @override

? Widget build(BuildContext context) {

? ? return Scaffold(

? ? ? appBar: AppBar(

? ? ? ? title: Text("ListView展示"),

? ? ? ),

? ? ? body: ListView.builder(

? ? ? ? itemCount: 100,

? ? ? ? itemExtent: 60,

? ? ? ? controller: _controller,

? ? ? ? itemBuilder: (BuildContext context, int index) {

? ? ? ? ? return ListTile(title: Text("item$index"));

? ? ? ? }

? ? ? ),

? ? ? floatingActionButton: !_isShowTop ? null : FloatingActionButton(

? ? ? ? child: Icon(Icons.arrow_upward),

? ? ? ? onPressed: () {

? ? ? ? ? _controller.animateTo(0, duration: Duration(milliseconds: 1000), curve: Curves.ease);

? ? ? ? },

? ? ? ),

? ? );

? }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容