ListView 是一個線性布局的widgets 列表.
ListView -extends->BoxScrollView -extends->ScrollView -extends->StatelessWidget
ListView是最常用的滑動組件。它在滾動方向上一個接一個地顯示它的孩子。在交叉軸中,需要孩子填充ListView。
如果子控件非空,使用 itemExtent
強制指定子控件高度范圍。通過itemExtent
設置值,比子控件自己決定范圍更高效,因為滾動機制可以通過設置的預設的itemExtent來節約工作,比如在滾動位置急劇變化的時候。
在構建ListView時有4中選擇:
- 利用顯示的自列表來構造
List<Widget>
。此構造函數適合于具有少量子元素的列表視圖,因為構造列表需要為可能顯示在列表視圖中的每個子元素執行工作,而不僅僅是那些實際可見的子元素。 -
ListView.builder
利用IndexedWidgetBuilder
來按需構造。這個構造函數適合于具有大量(或無限)子視圖的列表視圖,因為構建器只對那些實際可見的子視圖調用。 - 使用
ListView.separated
構造函數,采用兩個IndexedWidgetBuilder:itemBuilder
根據需要構建子項separatorBuilder
類似地構建出現在子項之間的分隔符子項。此構造函數適用于具有固定數量的子控件的列表視圖。 - 使用
ListView.custom
的SliverChildDelegate
構造,它提供了定制子模型的其他方面的能力。 例如,SliverChildDelegate
可以控制用于估計實際上不可見的孩子的大小的算法。
控制滾動的初始offset,可以通過設置ScrollController.initialScrollOffset
屬性。
默認情況下,ListView將自動填充列表的可滾動的末端,以避免MediaQuery的填充所指示的部分阻塞。若要避免此行為,請重寫可以空的padding
屬性。
ListView.builder demo
body: new ListView.builder(
padding: new EdgeInsets.all(5.0),
itemExtent: 50.0,
itemBuilder: (BuildContext context,int index){
return new Text("text $index");
},
),
這里的listView 可以無限往下滑動;)
ListView.separated demo
body: new ListView.separated(
itemBuilder: (BuildContext context, int index) {
return new Text("text $index");
},
separatorBuilder: (BuildContext context, int index) {
return new Container(height: 1.0, color: Colors.red);
},
itemCount: 40),
子結點的生命周期
1.創建
在布局列表時,可見的子元素、狀態和呈現對象將基于現有控件(例如當使用默認構造函數時)或延遲提供的控件(例如當使用ListView.builder構造函數時)延遲地創建。
2.銷毀
當從視圖滑出時,關聯的元素子樹、狀態和呈現對象將被銷毀。當向后滾動時,位于列表中相同位置的新子節點將與新元素、狀態和呈現對象一起延遲地重新創建。
3.銷毀時的數據保存
為了保存子元素在視圖中滾動和退出視圖時的狀態,可以做以下選擇:
1> 將與UI狀態驅動無關的業務邏輯從列表子子樹中移出。例如,如果一個列表包含來自高速緩存的網絡響應的帶有上投票數的帖子,那么將帖子列表和上投票數存儲在列表外部的數據模型中。讓列表子UI子樹很容易從真實模型對象的源中重新創建。使用子控件子樹中的StatefulWidget
只存儲瞬時UI狀態。
2> 讓KeepAlive
作為需要保存的列表子控件子樹的root結點。KeepAlive
使得孩子子樹的頂部結點渲染對象的子結點保持存活。當關聯的頂部渲染對象滾動到視圖之外時,列表將子對象的渲染對象(以及通過擴展,其關聯的元素和狀態)保存在高速緩存列表中,而不是銷毀它們。當滾動回到視圖中時,渲染對象將按照當前現狀被重新繪制(如果在中間階段沒有被標記為臟)。
這只在addAutomaticKeepAlives
和addRepaintBoundaries
為false的情況下有效,因為這些參數導致ListView將每個子小部件子樹與其他小部件包裝在一起。
3> 使用AutomaticKeepAlive
控件(當addautomatickeepalives
設置為ture的時候默認會插入)。而不是向KeepAlive
一樣,當滑出屏幕的無條件的緩存孩子的子樹,AutomaticKeepAlive
可以讓子樹的派生的邏輯控制是否需要緩存該子樹。
例如,EditableText
會在它有輸入焦點時發送子結點子樹以便保持存活狀態。 如果它沒有焦點,并且沒有其他派生類通過KeepAliveNotification
發出保持活動的信號,則滾動選擇時將清除列表子元素子樹。
AutomaticKeepAlive
派生類通常使用AutomaticKeepAliveClientMixin
發信號通知它保持活動狀態,然后實現wantKeepAlive
getter并調用updateKeepAlive
。
換到CustomScrollView
ListView基本上是一個CustomScrollView,在CustomScrollView.slivers屬性中僅僅有一個SliverList。
如果ListView不滿足需求,例如因為滾動視圖既有列表又有網格,或者因為列表要與SliverAppBar等組合在一起,所以直接將代碼從使用ListView移植到使用 CustomScrollView直接。
ListView上的key,scrollDirection,reverse,controller,primary,physics和shrinkWrap屬性直接映射到CustomScrollView上具有相同名稱的屬性。
CustomScrollView.slivers屬性應該是包含SliverList或SliverFixedExtentList的列表; 如果是前者,ListView上的itemExtent為null,如果是后者itemExtent不為null。
ListView上的childrenDelegate屬性對應于SliverList.delegate(或SliverFixedExtentList.delegate)屬性。 新的ListView構造函數的children參數對應于childrenDelegate是具有相同參數的SliverChildListDelegate。 新的ListView.builder構造函數的itemBuilder和childCount參數對應于childrenDelegate是一個帶有匹配參數的SliverChildBuilderDelegate。
padding屬性對應于在CustomScrollView.slivers屬性中具有SliverPadding而不是列表本身,并且使SliverList成為SliverPadding的子級。
CustomScrollViews不會自動避免像ListView這樣的MediaQuery障礙。 要重現該行為,請將slivers包裹在SliverSafeAreas中。
將代碼移植到使用CustomScrollView后,可以將其他slivers(例如SliverGrid或SliverAppBar)放入CustomScrollView.slivers列表中。
demo
body: new 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'),
],
),
body: new CustomScrollView(
shrinkWrap: true,
slivers: <Widget>[
new SliverPadding(
padding: const EdgeInsets.all(20.0),
sliver: new SliverList(
delegate: new SliverChildListDelegate(<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'),
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'),
])),
)
],
),