2016-01-12 18 views
11

我想在顯示數據時更新RecyclerView,在我的情況下,我顯示帶或不帶標籤的圖像。RecyclerView - 獲取所有現有視圖/查看者

默認情況下,我在創建視圖持有人時設置了標籤的可見性,這很好,但我希望用戶在顯示RecyclerView時通過菜單更改標籤可見性,所以我想手動更新可見性RecyclerView中的所有現有視圖。

我能以某種方式獲得所有現有Views嗎?我需要所有,不僅是可見的,我不希望以後回收View不更新...

+0

您是否有任何參數知道標籤是否可見或不在onBindViewHolder中?你應該檢查這個參數。更新菜單中的參數並設置adapter.notifyDataSetChanged – Chol

+0

我正在閱讀首選項,所以我想這樣做一次,而不是總是......我可以用適配器內部的布爾值來做到這一點,沒有想想實際上...... – prom85

+0

這個參數對於所有的項目都是一樣的嗎?或者可以根據項目有所不同? – Chol

回答

8

在adaptater類:

Boolean isVisible = false; 

public CustomAdapter(boolean isVisible) { 
    this.isVisible= isVisible; 
} 
    @Override 
    public void onBindViewHolder(ViewHolder holder, final int position) { 
    ... 

     if (isVisible){ 
      //setVisibility(View.VISIBLE) 
     }else{ 
     //setVisibility(View.INVISIBLE 
     } 
    } 

public void updateVisibility(boolean newValue){ 
isVisible= newValue; 
} 

Activity要更新其中適配器被實例化的價值:

adapter.updateVisibility(false); 
adapter.notifydataSetChanged(); 
+1

在'updateVisibility'中,你必須添加'notifyDataSetChanged()',但是這個工作正常,這就是我目前的解決方案......對我而言,它似乎並不完美,用戶很少改變可見性,而他幾乎總是滾動,因此始終設置可見性對我來說並不是最有效的解決方案...... – prom85

+0

@ prom85,在View類中有一些檢查可見性已更改,所以如果您調用具有相同值的'setVisibility',它不是問題。 – dilix

+0

@dilix,我不知道...然後我會堅持這個解決方案... – prom85

2

所有現有的視圖是可見的,加上一些視圖緩存由RecyclerView。您可以訪問所有可見View就像那樣:

View child; 
for (int i = 0; i < mRecycler.getChildCount(); i++) { 
    child = mRecycler.getChildAt(i); 
    //In case you need to access ViewHolder: 
    mRecycler.getChildViewHolder(child); 
} 

即使你訪問緩存View就是他們不是在綁定到數據還沒有,所以你不會知道,如果標籤應該是可見或不可見。只需在onBindViewHolder中設置其餘Views的標籤可見性即可。

View的其餘部分根本不存在,所以即使它們對所有人都是相同的標籤可見性狀態,您也無法更改任何關於它們的內容。

+2

這是行不通的,如果我這樣做,並不是所有的緩存視圖都會返回... – prom85

+0

我在哪裏寫了這個信息,讓您可以訪問**緩存的**視圖?無論如何,訪問它們都沒有意義。只需修改** visible **視圖,就像我上面所說的那樣,其餘的應該在'RecyclerView'需要時在'onBindViewHolder'中修改。 – InTwoMinds

+0

您編寫了「加上緩存的一些視圖」...我沒有看到您繼續只引用可見視圖。如果我修改視圖,我也必須修改所有緩存的視圖。當'RecyclerView'回收一個緩存視圖時,我希望它已經具有標籤所需的可見性,這樣我就不必一直將其設置在'onBindView'中......否則我不需要直接修改視圖並且只能在'onBindView'上只做這個... – prom85

26

首先,你需要獲得顯示各方面的意見指數,然後你需要去在每個,並使用每個視圖的viewHolder:

final int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition(); 
final int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); 
for (int i = firstVisibleItemPosition; i <= lastVisibleItemPosition; ++i) { 
    ViewHolder holder = (ViewHolder) mRecyclerView.findViewHolderForAdapterPosition(i); 
    ... 
    } 

編輯:它似乎並不總是返回您可能要處理的所有ViewHolders。這似乎是一個更穩定的解決方案:

for (int childCount = recyclerView.getChildCount(), i = 0; i < childCount; ++i) { 
    final ViewHolder holder = recyclerView.getChildViewHolder(mRecyclerView.getChildAt(i)); 
    ... 
    } 
+1

這是「獲取所有現有視圖/查看者」問題的正確答案,以及我所需要的。非常感謝! –

+0

如果說明如何獲得對layoutManager變量的引用,此答案會更有幫助。 –

+1

@JasonTyler爲了使用一個RecyclerView,你總是創建一個LayoutManager實例,所以你之前有它。這裏有一種方法來創建它,像垂直列表一樣工作(但同樣需要選擇使用哪一個):LayoutManager layoutManager = new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false) –

9
  • 更新整個適配器列表大小與notifyDataSetChanged()不方便。
  • 獲取所有當前的RecyclerView子元素(即所有可見項目)是不夠的:存在不可見的綁定視圖持有者:在啓動加載後,通常會在最後一個可見位置上綁定2或3個項目(具體取決於你的LayoutManager)。

我只是嘗試看我把日誌,RV結合更多的項目是不可見的,事實上,我發現沒有辦法對它們進行檢索。我結束了對緩存SetList那些ViewHolders在onBindViewHolder()非緩存他們onViewRecycled()

private Set<AbstractViewHolder> mBoundViewHolders = new HashSet<>(); 
private int mVisibility = View.VISIBILE; 

// So you can have access from the Activity/Fragment 
public Set<AbstractViewHolder> getAllBoundViewHolders() { 
    return Collections.unmodifiableSet(mBoundViewHolders); 
} 

@Override 
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads) { 
    // Binding code 
    ... 
    holder.view.setVisibility(mVisibility); 

    // Caching VH 
    mBoundViewHolders.add((AbstractViewHolder) holder); 
} 

@Override 
public void onViewRecycled(RecyclerView.ViewHolder holder) { 
    // Uncaching VH 
    mBoundViewHolders.remove(holder); 
} 

// Your method becomes 
public void updateVisibility(int visibility) { 
    mVisibility = visibility; 
    for (AbstractViewHolder holder : mBoundViewHolders) { 
     holder.updateVisibility(visibility); 
    } 
} 

實現你的接口或抽象ViewHolder這樣你就可以打電話給你的方法。 通過這種方式,您可以訪問您的ViewHolder內容。


這是我在做FlexibleAdapter取消選擇的項目調用notifyItemRangeChanged()。如果用戶有動畫,所有的都會被執行,當我調用我的方法toggleActivation()時,還會加上背景變化。

如果您知道更好的方法來檢索所有綁定的VH,請告訴我。

+0

如果不是添加和刪除到集合中,我只是將所有ViewHolders存儲在onCreateViewHolder中會發生什麼? –

+0

@androiddeveloper在我的庫中,它不能工作,因爲VH尚未創建。但是您可以嘗試查看適配器中發生的情況。 – Davidea

+0

@Davidea我以前沒有給你這個答案!良好的解決方法的人! –

0

所有上述解決方案只給出可見的持有者,但實際上有2-3個其他持有者被綁定但不可見。爲了讓那些爲好, 最簡單的,我能想到的準確的方式來獲得所有的持有人是:

int lastBoundHolderPosition = -1; 
int lastDetachedHolderPosition = -1; 

public void onBindViewHolder(final MyViewHolder holder, int position) { 
    lastBoundHolderPosition = position; 
    //Your implementation 
} 
public void onViewDetachedFromWindow(MyViewHolder holder){ 
    lastDetachedHolderPosition = holder.holder.getAdapterPosition(); 
} 

當你想所有的適配器可見(加約束,但不可見):

if(lastDetachedHolderPosition == -1){ 
    for(pos = 0; pos <= lastDetachedHolderPosition; pos++){ 
     ViewHolder holder = (ViewHolder) mRecyclerView.findViewHolderForAdapterPosition(pos); 
    } 
}else{ 
    if(lastBoundHolderPosition > lastDetachedHolderPosition){ //Scroll down 
     //get all the bound holders 
     for(int pos = lastDetachedHolderPosition + 1; pos <= lastBoundHolderPosition; pos++){ 
      ViewHolder holder = (ViewHolder) mRecyclerView.findViewHolderForAdapterPosition(pos); 
     } 
    }else{ //Scroll up 
     //get all the bound holders 
     for(int pos = lastBoundHolderPosition ; pos <= lastDetachedHolderPosition-1; pos++){ 
      ViewHolder holder = (ViewHolder) mRecyclerView.findViewHolderForAdapterPosition(pos); 
     } 

    } 
} 
+0

如何在不滾動的情況下獲取查看者?例如,點擊按鈕? –

+0

@androiddeveloper編輯,以滿足這一要求。 –

+0

hmmm ...另一個類似的方法是擁有一組ViewHolders,這也可以避免調用「findViewHolderForAdapterPosition」。可以更短,可能會更有效一點。不是? –