Flutter給我們提供了豐富的控件和控制方法,但是也有不少問題,就這兩天,我就遇到去獲取ListView第一個可見Item的Position的問題,Flutter並沒有提供方法,只能我們想辦法,我記得有大佬說過ListView和Android的RecyleView一樣,那ListView的ItemBuilder肯定是用多少創建多少,用哪個創建哪個,抱着試試的態度,我在ItemBuilder打印了一下,果然,他只創建當前要用的Item,下來我們看看我的思路
首先 我們先創建一個List來保存Position,在ItemBuilder裏面將創建的Item的位置Add到List裏面,然後建一個int類型的變量來保存初始化時創建的最後一個Item的位置(初始化的時候List爲空 只會保存最後一個item的position)
大家儘量把cacheEctent的值調小,緩存越小,後面獲取position越快
List<int> positions;
int memoryPosition;
child: new ListView.builder(
cacheExtent: 30.0,
itemBuilder: (context, index) {
if(positions!=null) {
if (index > positions.last) {
positions.removeAt(0);
positions.add(index);
} else if (index < positions.first) {
positions.removeLast();
positions.insert(0, index);
}
}else{
memoryPosition=index;
}
},),
好了,我們現在知道屏幕可顯示+緩存的有多少個Item了,我們找個合適的時機將所有Position緩存到List裏面,後面List變化可根據上面的代碼自動調整它的頭和尾,我是在NotificationListener的ScroStartNotification裏面緩存Position的,看代碼
new NotificationListener(
onNotification: (notification){
if(notification is ScrollStartNotification){
if(positions==null) {
positions=new List();
for(int i=0 ;i<=memoryPosition;i++){
positions.add(i);
}
}
}
},
child: new ListView.builder(),
這樣我們就知道頭和尾了,並實時更新,可是頭不一定是第一個可見Item,有可能是緩存的item,那我們怎麼辦呢,
我當時在想 我在調用時 如果我讓 ListView在屏幕的位置 和 Item在屏幕中的位置+Item的高度 做比較 如果Item可見 ,那麼Item在屏幕中的位置+Item的高度肯定大於ListView在屏幕的位置 (大家別忘了給ListView和它的Item們設置Key喲),好了,我們看代碼
int firstChildPosition=positions.first;
int lastChildPosition=positions.last;
double chileGlobalPositionY;
double chileHeight;
//獲取ListView在屏幕中的位置
double listViewGlobalPositionY=listViewKey.currentContext.findRenderObject().getTransformTo(null).getTranslation().y;
for(int i=firstChildPosition;i<=lastChildPosition;i++){
if(adsorptionDatas[i].adsorptionKey.currentContext==null){
continue;
}
//子控件在屏幕中的位置 用於計算第一個可見Item的位置
chileGlobalPositionY=adsorptionDatas[i].adsorptionKey.currentContext.findRenderObject().getTransformTo(null).getTranslation().y;
//控件高度 用於計算第一個可見Item的位置
chileHeight=adsorptionDatas[i].adsorptionKey.currentContext.findRenderObject().paintBounds.size.height;
//如果在屏幕中可見
if(chileGlobalPositionY+chileHeight>listViewGlobalPositionY){
//TODO i就是第一個可見Item的位置
break;
}
}
這樣,我們的第一個可見Item的位置就獲取到了
詳細代碼可參考https://github.com/baoolong/PullToRefresh 吸頂佈局模塊的代碼