需求:
- 點(diǎn)擊一個(gè)cell, 會(huì)調(diào)用
didSelectItemAtIndexPath:
方法,然后點(diǎn)擊另外一個(gè)cell,首先會(huì)調(diào)用didDeselectItemAtIndexPath:
這個(gè)方法,然后在調(diào)用didSelectItemAtIndexPath:
方法
問題:
- 當(dāng)然實(shí)現(xiàn)這個(gè)需求非常容易,但是當(dāng)你在
didSelectItemAtIndexPath
中調(diào)用reloadItemsAtIndexPaths
或者reloadData
這兩個(gè)方法(經(jīng)常在這個(gè)方法中我們用來修改模型數(shù)據(jù),并使用這兩個(gè)方法來刷新cell上面的顯示),來刷新cell上面的數(shù)據(jù)的時(shí)候,就會(huì)發(fā)現(xiàn),didDeselectItemAtIndexPath
這個(gè)方法不會(huì)調(diào)用了.
原因
- 我稍微分析了下原因.在調(diào)用
reloadItemsAtIndexPaths
或者reloadData
,系統(tǒng)內(nèi)部是會(huì)調(diào)用數(shù)據(jù)源方法cellForItemAtIndexPath:
, 而在這個(gè)方法里面,cell的selected
屬性又重新被初始化為NO了,所以此時(shí)cell的是處于非選中狀態(tài)的,自然就不會(huì)調(diào)用didDeselectItemAtIndexPath:
這個(gè)方法來取消選中.
解決方法分析
- 找到了原因,那么我們開始想辦法.
- 我們也許可以在
cellForItemAtIndexPath:
這個(gè)方法中手動(dòng)來設(shè)置cell的狀態(tài)(這里設(shè)置cell的狀態(tài)就是cell的最終狀態(tài),因?yàn)檫@個(gè)方法最后調(diào)用的).我們馬上就可以想到有2個(gè)方法也許可以修改cell的selected
屬性-
第一種: cell的
selected
屬性: 讓我們看看官方的解釋This property manages the selection state of the cell only. The default value of this property is NO, which indicates that the cell is not selected.
-
You typically do not set the value of this property directly. Changing the value of this property programmatically does not change the appearance of the cell. The preferred way to select the cell and highlight it is to use the selection methods of the collection view object.
這個(gè)屬性僅僅是用于管理cell的選中狀態(tài).默認(rèn)這個(gè)值為NO.意味著cell默認(rèn)情況下是沒有被選中的.
通常情況下,不要直接設(shè)置這個(gè)屬性.使用代碼來改變這個(gè)值并不會(huì)改變cell的外觀.選中cell,并讓cell顯示高亮狀態(tài)最好的方法就是調(diào)用UICollectionView相關(guān)selection方法來實(shí)現(xiàn).
```
- 官方也建議我們不要直接來設(shè)置,直接設(shè)置的話有可能并不會(huì)達(dá)到你想要的效果.經(jīng)過我的測試,直接設(shè)置確實(shí)沒有作用.同學(xué)們可以自己去試一下
- 第二種: -[UICollectionView selectItemAtIndexPath:animated:scrollPosition:]
- 這個(gè)方法可能就是蘋果官方建議的通過UICollectionView的對(duì)象方法來設(shè)置cell的選中狀態(tài).
- 還是讓我們看看官方的解釋
```objc
If the allowsSelection property is NO, calling this method has no effect. If there is an existing selection with a different index path and the allowsMultipleSelection property is NO, calling this method replaces the previous selection.
This method does not cause any selection-related delegate methods to be called.
如果allowsSelection屬性為NO, 調(diào)用這個(gè)方法沒有任何效果.
如果有任何另外一個(gè)已經(jīng)被選中cell(官方的說明是另外一個(gè)索引, 同一個(gè)意思)并且allowsMultipleSelection(允許多項(xiàng)選擇)這個(gè)屬性為NO, 那么調(diào)用這個(gè)方法會(huì)取代那個(gè)cell的選中狀態(tài).
也就是說當(dāng) allowsSelection = YES (默認(rèn)就是YES), allowsMultipleSelection = NO(這個(gè)也是默認(rèn)設(shè)置), 調(diào)用這個(gè)方法就會(huì)取消上一個(gè)cell的選中狀態(tài),然后讓當(dāng)前的cell選中.
```
- 看完官方的解釋,相信大家都明白了,剛好就是我們需要的屬性
最終解決方案
-
綜上所述, 如果你在
didSelectItemAtIndexPath:
和didDeselectItemAtIndexPath
這兩個(gè)方法中調(diào)用了reloadItemsAtIndexPaths
或者reloadData
這兩個(gè)方法來刷新cell上面顯示的數(shù)據(jù),但是發(fā)現(xiàn),didDeselectItemAtIndexPath
這個(gè)代理方法并沒有調(diào)用,你只需要做出如下的配置即可// 這兩個(gè)屬性都是默認(rèn)配置的,如果你沒有修改的話,就不用寫 allowsSelection = YES; allowsMultipleSelection = NO; - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
// 需要配置的代碼
[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
}
```