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

Flutter滾動組件之ListView使用方法詳解

 更新時間:2022年03月22日 17:07:39   作者:PuTTY本無樹  
這篇文章主要為大家詳細(xì)介紹了Flutter滾動組件之ListView的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

ListView

ListView是最常用的可滾動組件之一,它可以沿一個方向線性排布所有子組件,并且它也支持基于Sliver的延遲構(gòu)建模型。我們看看ListView的默認(rèn)構(gòu)造函數(shù)定義:

ListView({
? ... ?
? //可滾動widget公共參數(shù)
? Axis scrollDirection = Axis.vertical,
? bool reverse = false,
? ScrollController controller,
? bool primary,
? ScrollPhysics physics,
? EdgeInsetsGeometry padding,

? //ListView各個構(gòu)造函數(shù)的共同參數(shù) ?
? double itemExtent,
? bool shrinkWrap = false,
? bool addAutomaticKeepAlives = true,
? bool addRepaintBoundaries = true,
? double cacheExtent,

? //子widget列表
? List<Widget> children = const <Widget>[],
})

上面參數(shù)分為兩組:第一組是可滾動組件的公共參數(shù),前面已經(jīng)介紹過,不再贅述;第二組是ListView各個構(gòu)造函數(shù)(ListView有多個構(gòu)造函數(shù))的共同參數(shù),我們重點(diǎn)來看看這些參數(shù),:

  • itemExtent:該參數(shù)如果不為null,則會強(qiáng)制children的“長度”為itemExtent的值;這里的“長度”是指滾動方向上子組件的長度,也就是說如果滾動方向是垂直方向,則itemExtent代表子組件的高度;如果滾動方向為水平方向,則itemExtent就代表子組件的寬度。在ListView中,指定itemExtent比讓子組件自己決定自身長度會更高效,這是因為指定itemExtent后,滾動系統(tǒng)可以提前知道列表的長度,而無需每次構(gòu)建子組件時都去再計算一下,尤其是在滾動位置頻繁變化時(滾動系統(tǒng)需要頻繁去計算列表高度)。
  • shrinkWrap:該屬性表示是否根據(jù)子組件的總長度來設(shè)置ListView的長度,默認(rèn)值為false。默認(rèn)情況下,ListView的會在滾動方向盡可能多的占用空間。當(dāng)ListView在一個無邊界(滾動方向上)的容器中時,shrinkWrap必須為true。
  • addAutomaticKeepAlives:該屬性表示是否將列表項(子組件)包裹在AutomaticKeepAlive組件中;典型地,在一個懶加載列表中,如果將列表項包裹在AutomaticKeepAlive中,在該列表項滑出視口時它也不會被GC(垃圾回收),它會使用KeepAliveNotification來保存其狀態(tài)。如果列表項自己維護(hù)其KeepAlive狀態(tài),那么此參數(shù)必須置為false。
  • addRepaintBoundaries:該屬性表示是否將列表項(子組件)包裹在RepaintBoundary組件中。當(dāng)可滾動組件滾動時,將列表項包裹在RepaintBoundary中可以避免列表項重繪,但是當(dāng)列表項重繪的開銷非常?。ㄈ缫粋€顏色塊,或者一個較短的文本)時,不添加RepaintBoundary反而會更高效。和addAutomaticKeepAlive一樣,如果列表項自己維護(hù)其KeepAlive狀態(tài),那么此參數(shù)必須置為false。

注意:上面這些參數(shù)并非ListView特有,其它可滾動組件也可能會擁有這些參數(shù),它們的含義是相同的。

默認(rèn)構(gòu)造函數(shù)

默認(rèn)構(gòu)造函數(shù)有一個children參數(shù),它接受一個Widget列表(List)。這種方式適合只有少量的子組件的情況,因為這種方式需要將所有children都提前創(chuàng)建好(這需要做大量工作),而不是等到子widget真正顯示的時候再創(chuàng)建,也就是說通過默認(rèn)構(gòu)造函數(shù)構(gòu)建的ListView沒有應(yīng)用基于Sliver的懶加載模型。實際上通過此方式創(chuàng)建的ListView和使用SingleChildScrollView+Column的方式?jīng)]有本質(zhì)的區(qū)別。下面是一個例子:

ListView(
? shrinkWrap: true,?
? padding: const EdgeInsets.all(20.0),
? children: <Widget>[
? ? const Text('I\'m dedicating every day to you'),
? ? const Text('Domestic life was never quite my style'),
? ? const Text('When you smile, you knock me out, I fall apart'),
? ? const Text('And I thought I was so smart'),
? ],
);

再次強(qiáng)調(diào),可滾動組件通過一個List來作為其children屬性時,只適用于子組件較少的情況,這是一個通用規(guī)律,并非ListView自己的特性,像GridView也是如此。

ListView.builder

ListView.builder適合列表項比較多(或者無限)的情況,因為只有當(dāng)子組件真正顯示的時候才會被創(chuàng)建,也就說通過該構(gòu)造函數(shù)創(chuàng)建的ListView是支持基于Sliver的懶加載模型的。下面看一下ListView.builder的核心參數(shù)列表:

ListView.builder({
? // ListView公共參數(shù)已省略 ?
? ...
? @required IndexedWidgetBuilder itemBuilder,
? int itemCount,
? ...
})
  • itemBuilder:它是列表項的構(gòu)建器,類型為IndexedWidgetBuilder,返回值為一個widget。當(dāng)列表滾動到具體的index位置時,會調(diào)用該構(gòu)建器構(gòu)建列表項。
  • itemCount:列表項的數(shù)量,如果為null,則為無限列表。

可滾動組件的構(gòu)造函數(shù)如果需要一個列表項Builder,那么通過該構(gòu)造函數(shù)構(gòu)建的可滾動組件通常就是支持基于Sliver的懶加載模型的,反之則不支持,這是個一般規(guī)律。我們在后面在介紹可滾動組件的構(gòu)造函數(shù)時將不再專門說明其是否支持基于Sliver的懶加載模型了。
下面看一個例子:

ListView.builder(
? ? itemCount: 100,
? ? itemExtent: 50.0, //強(qiáng)制高度為50.0
? ? itemBuilder: (BuildContext context, int index) {
? ? ? return ListTile(title: Text("$index"));
? ? }
);

運(yùn)行效果如圖所示:

ListView.separated

ListView.separated可以在生成的列表項之間添加一個分割組件,它比ListView.builder多了一個separatorBuilder參數(shù),該參數(shù)是一個分割組件生成器。

下面我們看一個例子:奇數(shù)行添加一條藍(lán)色下劃線,偶數(shù)行添加一條綠色下劃線。

class ListView3 extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? //下劃線widget預(yù)定義以供復(fù)用。 ?
? ? Widget divider1=Divider(color: Colors.blue,);
? ? Widget divider2=Divider(color: Colors.green);
? ? return ListView.separated(
? ? ? ? itemCount: 100,
? ? ? ? //列表項構(gòu)造器
? ? ? ? itemBuilder: (BuildContext context, int index) {
? ? ? ? ? return ListTile(title: Text("$index"));
? ? ? ? },
? ? ? ? //分割器構(gòu)造器
? ? ? ? separatorBuilder: (BuildContext context, int index) {
? ? ? ? ? return index%2==0?divider1:divider2;
? ? ? ? },
? ? );
? }
}

運(yùn)行效果如圖:

實例:無限加載列表

假設(shè)我們要從數(shù)據(jù)源異步分批拉取一些數(shù)據(jù),然后用ListView展示,當(dāng)我們滑動到列表末尾時,判斷是否需要再去拉取數(shù)據(jù),如果是,則去拉取,拉取過程中在表尾顯示一個loading,拉取成功后將數(shù)據(jù)插入列表;如果不需要再去拉取,則在表尾提示"沒有更多"。代碼如下:

class InfiniteListView extends StatefulWidget {
? @override
? _InfiniteListViewState createState() => new _InfiniteListViewState();
}

class _InfiniteListViewState extends State<InfiniteListView> {
? static const loadingTag = "##loading##"; //表尾標(biāo)記
? var _words = <String>[loadingTag];

? @override
? void initState() {
? ? super.initState();
? ? _retrieveData();
? }

? @override
? Widget build(BuildContext context) {
? ? return ListView.separated(
? ? ? itemCount: _words.length,
? ? ? itemBuilder: (context, index) {
? ? ? ? //如果到了表尾
? ? ? ? if (_words[index] == loadingTag) {
? ? ? ? ? //不足100條,繼續(xù)獲取數(shù)據(jù)
? ? ? ? ? if (_words.length - 1 < 100) {
? ? ? ? ? ? //獲取數(shù)據(jù)
? ? ? ? ? ? _retrieveData();
? ? ? ? ? ? //加載時顯示loading
? ? ? ? ? ? return Container(
? ? ? ? ? ? ? padding: const EdgeInsets.all(16.0),
? ? ? ? ? ? ? alignment: Alignment.center,
? ? ? ? ? ? ? child: SizedBox(
? ? ? ? ? ? ? ? ? width: 24.0,
? ? ? ? ? ? ? ? ? height: 24.0,
? ? ? ? ? ? ? ? ? child: CircularProgressIndicator(strokeWidth: 2.0)
? ? ? ? ? ? ? ),
? ? ? ? ? ? );
? ? ? ? ? } else {
? ? ? ? ? ? //已經(jīng)加載了100條數(shù)據(jù),不再獲取數(shù)據(jù)。
? ? ? ? ? ? return Container(
? ? ? ? ? ? ? ? alignment: Alignment.center,
? ? ? ? ? ? ? ? padding: EdgeInsets.all(16.0),
? ? ? ? ? ? ? ? child: Text("沒有更多了", style: TextStyle(color: Colors.grey),)
? ? ? ? ? ? );
? ? ? ? ? }
? ? ? ? }
? ? ? ? //顯示單詞列表項
? ? ? ? return ListTile(title: Text(_words[index]));
? ? ? },
? ? ? separatorBuilder: (context, index) => Divider(height: .0),
? ? );
? }

? void _retrieveData() {
? ? Future.delayed(Duration(seconds: 2)).then((e) {
? ? ? _words.insertAll(_words.length - 1,
? ? ? ? ? //每次生成20個單詞
? ? ? ? ? generateWordPairs().take(20).map((e) => e.asPascalCase).toList()
? ? ? );
? ? ? setState(() {
? ? ? ? //重新構(gòu)建列表
? ? ? });
? ? });
? }

}

運(yùn)行后效果如圖所示:

代碼比較簡單,可以參照代碼中的注釋理解。需要說明的是,_retrieveData()的功能是模擬從數(shù)據(jù)源異步獲取數(shù)據(jù),我們使用english_words包的generateWordPairs()方法每次生成20個單詞。

添加固定列表頭

很多時候我們需要給列表添加一個固定表頭,比如我們想實現(xiàn)一個商品列表,需要在列表頂部添加一個“商品列表”標(biāo)題,期望的效果如圖所示:

我們按照之前經(jīng)驗,寫出如下代碼:

@override
Widget build(BuildContext context) {
? return Column(children: <Widget>[
? ? ListTile(title:Text("商品列表")),
? ? ListView.builder(itemBuilder: (BuildContext context, int index) {
? ? ? ? return ListTile(title: Text("$index"));
? ? }),
? ]);
}

然后運(yùn)行,發(fā)現(xiàn)并沒有出現(xiàn)我們期望的效果,相反觸發(fā)了一個異常;

Error caught by rendering library, thrown during performResize()。
Vertical viewport was given unbounded height ...

從異常信息中我們可以看到是因為ListView高度邊界無法確定引起,所以解決的辦法也很明顯,我們需要給ListView指定邊界,我們通過SizedBox指定一個列表高度看看是否生效:

... //省略無關(guān)代碼
SizedBox(
? ? height: 400, //指定列表高度為400
? ? child: ListView.builder(itemBuilder: (BuildContext context, int index) {
? ? ? ? return ListTile(title: Text("$index"));
? ? }),
),
...

運(yùn)行效果如圖所示:

可以看到,現(xiàn)在沒有觸發(fā)異常并且列表已經(jīng)顯示出來了,但是我們的手機(jī)屏幕高度要大于400,所以底部會有一些空白。那如果我們要實現(xiàn)列表鋪滿除表頭以外的屏幕空間應(yīng)該怎么做?直觀的方法是我們?nèi)討B(tài)計算,用屏幕高度減去狀態(tài)欄、導(dǎo)航欄、表頭的高度即為剩余屏幕高度,代碼如下:

... //省略無關(guān)代碼
SizedBox(
? //Material設(shè)計規(guī)范中狀態(tài)欄、導(dǎo)航欄、ListTile高度分別為24、56、56?
? height: MediaQuery.of(context).size.height-24-56-56,
? child: ListView.builder(itemBuilder: (BuildContext context, int index) {
? ? return ListTile(title: Text("$index"));
? }),
)
...

運(yùn)行效果如下圖所示:

可以看到,我們期望的效果實現(xiàn)了,但是這種方法并不優(yōu)雅,如果頁面布局發(fā)生變化,比如表頭布局調(diào)整導(dǎo)致表頭高度改變,那么剩余空間的高度就得重新計算。那么有什么方法可以自動拉伸ListView以填充屏幕剩余空間的方法嗎?當(dāng)然有!答案就是Flex。前面已經(jīng)介紹過在彈性布局中,可以使用Expanded自動拉伸組件大小,并且我們也說過Column是繼承自Flex的,所以我們可以直接使用Column+Expanded來實現(xiàn),代碼如下:

@override
Widget build(BuildContext context) {
? return Column(children: <Widget>[
? ? ListTile(title:Text("商品列表")),
? ? Expanded(
? ? ? child: ListView.builder(itemBuilder: (BuildContext context, int index) {
? ? ? ? return ListTile(title: Text("$index"));
? ? ? }),
? ? ),
? ]);
}

運(yùn)行后,和上圖一樣,完美實現(xiàn)了!

總結(jié):

本節(jié)主要介紹了ListView的一些公共參數(shù)以及常用的構(gòu)造函數(shù)。不同的構(gòu)造函數(shù)對應(yīng)了不同的列表項生成模型,如果需要自定義列表項生成模型,可以通過ListView.custom來自定義,它需要實現(xiàn)一個SliverChildDelegate用來給ListView生成列表項組件,更多詳情請參考API文檔。

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

相關(guān)文章

  • Android實現(xiàn)常見的驗證碼輸入框?qū)嵗a

    Android實現(xiàn)常見的驗證碼輸入框?qū)嵗a

    我們在開發(fā)APP的時候經(jīng)常要遇到輸入框,下面這篇文章主要給大家介紹了關(guān)于利用Android如何實現(xiàn)常見的驗證碼輸入框的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)下吧。
    2017-09-09
  • Android中使用開源框架Citypickerview實現(xiàn)省市區(qū)三級聯(lián)動選擇

    Android中使用開源框架Citypickerview實現(xiàn)省市區(qū)三級聯(lián)動選擇

    這篇文章主要介紹了Android中使用開源框架Citypickerview實現(xiàn)省市區(qū)三級聯(lián)動選擇效果,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-03-03
  • Android編程中EditText限制文字輸入的方法

    Android編程中EditText限制文字輸入的方法

    這篇文章主要介紹了Android編程中EditText限制文字輸入的方法,涉及Android針對EditText的監(jiān)聽技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11
  • Android原生集成RN最新版教程

    Android原生集成RN最新版教程

    這篇文章主要為大家介紹了Android原生集成RN最新版教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Android?Flutter實現(xiàn)自由落體彈跳動畫效果

    Android?Flutter實現(xiàn)自由落體彈跳動畫效果

    粒子運(yùn)動是將對象按照一定物理公式進(jìn)行的自定義軌跡運(yùn)動,與普通動畫不同的是,它沒有強(qiáng)制性的動畫開始到結(jié)束的時間概念。本文將利用Flutter實現(xiàn)自由落體彈跳動畫效果,感興趣的小伙伴可以學(xué)習(xí)一下
    2022-10-10
  • Android實現(xiàn)微信右側(cè)頂部下拉對話框

    Android實現(xiàn)微信右側(cè)頂部下拉對話框

    這篇文章主要為大家詳細(xì)介紹了Android實現(xiàn)微信右側(cè)頂部下拉對話框,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Android實現(xiàn)老虎機(jī)小游戲代碼示例

    Android實現(xiàn)老虎機(jī)小游戲代碼示例

    大家好,本篇文章主要講的是Android實現(xiàn)老虎機(jī)小游戲代碼示例,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • Android事件傳遞機(jī)制

    Android事件傳遞機(jī)制

    這篇文章主要介紹了Android事件傳遞機(jī)制的相關(guān)資料,需要的朋友可以參考下
    2016-02-02
  • Android 應(yīng)用中跳轉(zhuǎn)到應(yīng)用市場評分示例

    Android 應(yīng)用中跳轉(zhuǎn)到應(yīng)用市場評分示例

    本篇文章主要介紹了Android 應(yīng)用中跳轉(zhuǎn)到應(yīng)用市場評分示例,非常具有實用價值,需要的朋友可以參考下。
    2017-02-02
  • Flutter3.7新增Menu菜單組件的使用教程分享

    Flutter3.7新增Menu菜單組件的使用教程分享

    之前Flutter的菜單選擇、下拉菜單的支持非常簡單且不友好,對于非常常見的下拉菜單選擇功能是需要自己自定義實現(xiàn),今天看到Flutter3.7版本新增了一系列菜單的組件,馬上來試試
    2023-01-01

最新評論

铁岭市| 屏南县| 增城市| 新建县| 清镇市| 武宣县| 敦煌市| 泸州市| 青阳县| 丽水市| 泰宁县| 资讯 | 田东县| 遵义市| 吴川市| 崇明县| 蒲城县| 攀枝花市| 沅江市| 南京市| 崇信县| 尚志市| 翼城县| 陆丰市| 五大连池市| 芜湖市| 十堰市| 永定县| 镇平县| 顺义区| 遵义市| 屏山县| 高邑县| 阳信县| 双桥区| 巴塘县| 镶黄旗| 新干县| 分宜县| 阜宁县| 阿拉善盟|