51

セルの選択時に、セルの外観の変更を処理したい。私はデリゲートメソッドを考え出しましたcollectionView:didSelectItemAtIndexPath:&collectionView:didDeselectItemAtIndexPath:セルを編集する必要がある場所です。

-(void)collectionView:(UICollectionView *)collectionView 
       didSelectItemAtIndexPath:(NSIndexPath *)indexPath {

    DatasetCell *datasetCell = 
      (DatasetCell *)[collectionView cellForItemAtIndexPath:indexPath];

    [datasetCell replaceHeaderGradientWith:[UIColor skyBlueHeaderGradient]];
    datasetCell.backgroundColor = [UIColor skyBlueColor];
}

-(void)collectionView:(UICollectionView *)collectionView 
       didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {

    DatasetCell *datasetCell = 
      (DatasetCell *)[collectionView cellForItemAtIndexPath:indexPath];

    [datasetCell replaceHeaderGradientWith:[UIColor grayGradient]];
    datasetCell.backgroundColor = [UIColor myDarkGrayColor];
}

セルが再利用される場合を除いて、これは正常に機能します。インデックス(0、0)のセルを選択すると、外観が変わりますが、下にスクロールすると、別のセルが選択された状態になります。

UICollectionViewCellこのメソッドを使用して、セルを再利用-(void)prepareForReuseする準備をする (つまり、セルの外観を選択されていない状態に設定する) 必要があると思いますが、問題が生じます。

-(void)prepareForReuse {
    if ( self.selected ) {
        [self replaceHeaderGradientWith:[UIColor skyBlueHeaderGradient]];
        self.backgroundColor = [UIColor skyBlueColor];
    } else {
        [self replaceHeaderGradientWith:[UIColor grayGradient]];
        self.backgroundColor = [UIColor myDarkGrayColor];
    }
}

一番上までスクロールすると、インデックス (0, 0) のセルが選択解除された状態になります。

cell.backgroundView プロパティを使用したばかりのとき、これを防ぐには次のようにしました。

-(void)prepareForReuse {
    self.selected = FALSE;
}

選択状態は意図したとおりに機能しました。

何か案は?

4

12 に答える 12

75

あなたの観察は正しいです。この動作は、セルの再利用が原因で発生しています。ただし、 prepareForReuseで何もする必要はありません 。代わりにcellForItemでチェックを行い、それに応じてプロパティを設定してください。何かのようなもの..

 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cvCell" forIndexPath:indexPath];


if (cell.selected) {
     cell.backgroundColor = [UIColor blueColor]; // highlight selection 
}
else
{
     cell.backgroundColor = [UIColor redColor]; // Default color
}
return cell;
}

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath  {

    UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath];
    datasetCell.backgroundColor = [UIColor blueColor]; // highlight selection
 }  

 -(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {

UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath]; 
datasetCell.backgroundColor = [UIColor redColor]; // Default color
}
于 2013-04-02T07:26:14.793 に答える
25

セルのbackgroundViewとをセットアップすると、フレームワークがビューの切り替えを処理します。選択とハイライトの表示状態の管理 のselectedBackgroundView例を参照してください。

UIView* backgroundView = [[UIView alloc] initWithFrame:self.bounds];
backgroundView.backgroundColor = [UIColor redColor];
self.backgroundView = backgroundView;

UIView* selectedBGView = [[UIView alloc] initWithFrame:self.bounds];
selectedBGView.backgroundColor = [UIColor whiteColor];
self.selectedBackgroundView = selectedBGView;

UICollectionViewDelegate次のように、セルを強調表示して選択できるようにすることを実装するクラスでのみ必要です。

- (BOOL)collectionView:(UICollectionView *)collectionView
        shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (BOOL)collectionView:(UICollectionView *)collectionView
        shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath;
{
    return YES;
}

これはうまくいきます。

于 2013-10-03T11:58:06.903 に答える
24

UICollectionView は iOS 10 で変更され、上記のソリューションにいくつかの問題が発生しました。

ここに良いガイドがあります: https://littlebitesofcocoa.com/241-uicollectionview-cell-pre-fetching

セルが画面外に出た後もしばらく残るようになりました。didDeselectItemAt indexPathこれは、セルを調整するためにセルを取得できない場合があることを意味します。その後、更新もリサイクルもされずに画面に表示されます。prepareForReuseこのコーナーケースには役立ちません。

isPrefetchingEnabled最も簡単な解決策は、 falseに設定して新しいスクロールを無効にすることです。これにより、セルの表示の管理は cellForItemAt didSelect didDeselect以前と同じように機能します。

ただし、新しいスムーズ スクロール動作を維持したい場合は、以下を使用することをお勧めしますwillDisplay

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    let customCell = cell as! CustomCell
    if customCell.isSelected {
        customCell.select()
    } else {
        customCell.unselect()
    }
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
    //Don't even need to set selection-specific things here as recycled cells will also go through willDisplay
    return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath) as? CustomCell
    cell?.select()
}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath) as? CustomCell
    cell?.unselect() // <----- this can be null here, and the cell can still come back on screen!
}

上記を使用すると、セルが選択されているとき、画面上で選択解除されているとき、リサイクルされているとき、および再表示されているときにセルを制御できます。

于 2016-11-22T18:26:56.657 に答える
11

Anil は正しい方向に進んでいました (彼のソリューションは機能するはずです。私は彼とは別にこのソリューションを開発しました)。prepareForReuse:メソッドを使用してセルを に設定selectedFALSEcellForItemAtIndexPathセルのインデックスが「collectionView.indexPathsForSelectedItems」にあるかどうかを確認し、そうであれば強調表示します。

カスタムセルで:

-(void)prepareForReuse {
    self.selected = FALSE;
}

cellForItemAtIndexPath:再利用セルの強調表示と強調表示解除を処理するには、次のようにします。

if ([collectionView.indexPathsForSelectedItems containsObject:indexPath]) {
    [collectionView selectItemAtIndexPath:indexPath animated:FALSE scrollPosition:UICollectionViewScrollPositionNone];
    // Select Cell
}
else {
    // Set cell to non-highlight
}

そして、and でセルの強調表示と強調表示解除を処理しますdidDeselectItemAtIndexPath:didSelectItemAtIndexPath:

これは私にとって魅力のように機能します。

于 2013-06-07T19:08:10.887 に答える
6

私は水平スクロール コレクション ビュー (私は Tableview でコレクション ビューを使用しています) を持っていましたが、1 つのアイテムを選択して右にスクロールすると、次の表示セットの他のセルが自動的に選択されます。「選択」、強調表示などのカスタムセルプロパティを使用してこれを解決しようとしても役に立たなかったので、以下の解決策を思いつき、これがうまくいきました。

ステップ1:

選択したインデックスを格納する変数を collectionView に作成します。ここでは、selectedIndex というクラス レベルの変数を使用しています。

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

{

    MyCVCell *cell = (MyCVCell*)[collectionView dequeueReusableCellWithReuseIdentifier:@"MyCVCell" forIndexPath:indexPath];    

// When scrolling happens, set the selection status only if the index matches the selected Index

if (selectedIndex == indexPath.row) {

        cell.layer.borderWidth = 1.0;

        cell.layer.borderColor = [[UIColor redColor] CGColor];

    }
    else
    {
        // Turn off the selection
        cell.layer.borderWidth = 0.0;

    }
    return cell;

}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath

{
    MyCVCell *cell = (MyCVCell *)[collectionView cellForItemAtIndexPath:indexPath];
    // Set the index once user taps on a cell
    selectedIndex = indexPath.row;
    // Set the selection here so that selection of cell is shown to ur user immediately
    cell.layer.borderWidth = 1.0;
    cell.layer.borderColor = [[UIColor redColor] CGColor];
    [cell setNeedsDisplay];
}

- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath

{

    MyCVCell *cell = (MyCVCell *)[collectionView cellForItemAtIndexPath:indexPath];

    // Set the index to an invalid value so that the cells get deselected
    selectedIndex = -1;
    cell.layer.borderWidth = 0.0;
    [cell setNeedsDisplay];

}

-アヌープ

于 2014-05-08T05:42:00.137 に答える
2

カスタム セルで public メソッドを作成します。

- (void)showSelection:(BOOL)selection
{
    self.contentView.backgroundColor = selection ? [UIColor blueColor] : [UIColor white];
}

-prepareForReuse セル メソッドの再定義も記述します。

- (void)prepareForReuse
{
    [self showSelection:NO];
    [super prepareForReuse];
}

そして、ViewController には、-didSelectItemAtIndexPath で定義され、-didDeselectItemAtIndexPath で無効化された _selectedIndexPath 変数が必要です。

NSIndexPath *_selectedIndexPath;

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"Cell";
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];

    if (_selectedIndexPath) {
        [cell showSelection:[indexPath isEqual:_selectedIndexPath]];
    }
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
    [cell showSelection:![indexPath isEqual:_selectedIndexPath]];// on/off selection
    _selectedIndexPath = [indexPath isEqual:_selectedIndexPath] ? nil : indexPath;
}

- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
    [cell showSelection:NO];
    _selectedIndexPath = nil;
}
于 2014-07-11T09:34:06.877 に答える
1

iOS 9.3で@ stefanBソリューションのみが機能しました

ここで、Swift 2 用に変更する必要があるもの

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        //prepare your cell here..

        //Add background view for normal cell
        let backgroundView: UIView = UIView(frame: cell!.bounds)
        backgroundView.backgroundColor = UIColor.lightGrayColor()
        cell!.backgroundView = backgroundView

        //Add background view for selected cell
        let selectedBGView: UIView = UIView(frame: cell!.bounds)
        selectedBGView.backgroundColor = UIColor.redColor()
        cell!.selectedBackgroundView = selectedBGView

        return cell!
 }

 func collectionView(collectionView: UICollectionView, shouldHighlightItemAtIndexPath indexPath: NSIndexPath) -> Bool {
        return true
 }

 func collectionView(collectionView: UICollectionView, shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool {
        return true
 }
于 2016-04-26T08:48:09.730 に答える
0

セルの selectedBackgroundView を backgroundColor=x に設定するだけです。

セルをタップすると、選択したモードが自動的に変更され、背景色が x に変更されます。

于 2014-07-20T16:00:07.207 に答える
0

あなたの答え@ RDCに感謝します。

次のコードはSwift 3で動作します

// MARK: - UICollectionViewDataSource protocol
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    //prepare your cell here..
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! MyCell
    cell.myLabel.text =  "my text"

    //Add background view for normal cell
    let backgroundView: UIView = UIView(frame: cell.bounds)
    backgroundView.backgroundColor = UIColor.lightGray
    cell.backgroundView = backgroundView

    //Add background view for selected cell
    let selectedBGView: UIView = UIView(frame: cell.bounds)
    selectedBGView.backgroundColor = UIColor.green
    cell.selectedBackgroundView = selectedBGView

    return cell
}

// MARK: - UICollectionViewDelegate protocol
func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool {
    return true
}

func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
    return true
}
于 2016-10-18T13:35:29.890 に答える