Flutter ListView優雅的獲取第一個可見Item的Position

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 吸頂佈局模塊的代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章