Soru UICollectionView hücre seçimi ve hücre yeniden kullanımı


Hücre seçiminde hücre görünümünü değiştirmeyi istiyorum. Delege yöntemini düşündüm collectionView:didSelectItemAtIndexPath: & collectionView:didDeselectItemAtIndexPath: hücreyi nerede düzenleyeceğim.

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

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

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

ve

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

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

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

Bu, hücre yeniden kullanıldığında hariç, iyi çalışır. İndekste (0, 0) hücreyi seçersem, görünümü değiştirir ama ben aşağı doğru kaydırdığımda, seçilen durumda başka bir hücre var.

Kullanmam gerektiğine inanıyorum UICollectionViewCell yöntem -(void)prepareForReuse Yeniden kullanmak için hücreyi hazırlayın (yani hücre görünümünü seçilmemiş duruma ayarlayın), ancak bana zorluklar yaşatır.

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

En üste geri kaydırdığımda, dizindeki (0, 0) hücre seçimi kaldırılmış durumda.

Ben sadece cell.backgroundView özelliğini kullandığında, bunun olmasını önlemek için:

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

ve seçim durumu amaçlandığı gibi çalıştı.

Herhangi bir fikir?


44
2018-03-27 17:15


Menşei


Objective C'de TRUE / FALSE yerine YES / NO kullanmanız önerilir. - rounak
Belgelere göre çağırıyor olmalısın [super prepareForReuse]; aramanın içinden prepareForReuse. - Streeter
Bu sorunu nasıl çözdünüz? aynı problemi aldım - Anish 웃
bende aynı problem var ve çözemiyorum - Rawan


Cevaplar:


Gözlemin doğru. Bu davranış, hücrelerin yeniden kullanılması nedeniyle oluyor. Ama senle hiçbir şey yapmak zorunda değilsin prepareForReuse. Bunun yerine çekinizi yapın cellForItem ve özellikleri buna göre ayarlayın. Gibi bir şey..

 - (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
}

69
2018-04-02 07:26



@iPhoneProgrammatically neden? ne oldu? - Anil Varghese
Seçilen hücreler görüntü değişimi, ancak seçim kaydırırken değişir. - iPhone Programmatically
Herhangi bir sorunuz varsa, bunu ayrı bir soru olarak sorabilirsiniz .. Olası bir yolu önerdim .. Belirli bir durum için işe yarayabilir ya da çalışmayabilir .. Bir şey garanti edebilirim! - Anil Varghese
@ Anil Ya lütfen açıklayınız. - iPhone Programmatically
Mükemmel çalıştı teşekkürler! - Plot


Çerçeve sizin için görüşleri değiştirmeyi ele alacak hücrenizi kurduktan sonra backgroundView ve selectedBackgroundView, örneğe bakın Seçimler ve Önemli Noktalar için Görsel Durumu Yönetmek:

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;

sadece sizin uyguladığınız sınıfa ihtiyacınız var UICollectionViewDelegate Hücrelerin vurgulanıp seçilebilmesini sağlayın:

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

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

Bu bana çalışıyor.


23
2017-10-03 11:58



Bu iki yöntem (shouldHighlightItemAtIndexPath / shouldSelectItemAtIndexPath), UICollectionViewDelegate veri kaynağı değil - JakubKnejzlik
Çok teşekkür ederim, bu sadece benim için çalıştığım çözüm. - swiftBoy


UICollectionView, iOS 10'da, yukarıdaki çözümlere bazı sorunlar getirerek değişti.

İşte iyi bir rehber: https://littlebitesofcocoa.com/241-uicollectionview-cell-pre-fetching

Hücreler artık ekrandan çıktıktan sonra biraz kalıyor. Yani bazen bir hücreyi ele geçiremeyebiliriz. didDeselectItemAt indexPath bunu ayarlamak için. Ardından, güncelleme yapılmadan ve geri dönüştürülmeden ekranda görünebilir. prepareForReuse bu köşe kasasına yardım etmiyor.

En kolay çözüm, yeni kaydırma ayarını devre dışı bırakıyor isPrefetchingEnabled yanlış Bununla, hücrenin ekranını yönetme      cellForItemAt  didSelect  didDeselect eskiden olduğu gibi çalışır.

Ancak, yeni düzgün kaydırma davranışını tercih ederseniz kullanmak daha iyidir 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!
}

Yukarıdaki seçenekle, seçili olduğunda hücreyi kontrol edersiniz, ekranda seçilmemiş, geri dönüştürülür ve tekrar görüntülenir.


15
2017-11-22 18:26



iOS 10 için yapılan değişiklikler nedeniyle bu kabul edilen yanıt olmalı - jarrodparkes


Anil doğru yoldaydı (çözümü işe yarayacak gibi görünüyor, bu çözümü kendi başına geliştirdim). Hala kullanıyorum prepareForReuse: hücrenin ayarlanması yöntemi selected için FALSEsonra cellForItemAtIndexPath Hücrenin dizininin "collectionView.indexPathsForSelectedItems" içinde olup olmadığını kontrol et, eğer öyleyse, vurgula.

Özel hücrede:

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

İçinde cellForItemAtIndexPath: vurgulama ve dehighlighting yeniden kullanım hücreleri ele almak için:

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

Ve sonra hücre vurgulama ve dehighlighting işlemek didDeselectItemAtIndexPath: ve didSelectItemAtIndexPath:

Bu benim için bir çekicilik gibi çalışır.


10
2018-06-07 19:08



Tek ve en iyi yol - orkenstein
Yeniden kullanıma hazırlanmak için süper aramayı unutmayın! - NYC Tech Engineer
PrepareForReuse kullanarak çalıştı! Ama @NYCTechEngineer'ın dediği gibi, süper çağrıyı da unutma. Teşekkürler! - Crashalot


Bir yatay kaydırma koleksiyonu görünümü (Tablo görünümünde koleksiyon görünümü kullanıyorum) vardı ve bir öğeyi seçip sağa doğru kaydırdığımda, bir sonraki görünür kümedeki diğer bazı hücreler otomatik olarak seçildiğinde, benimle yeniden kullanımda sorun yaşıyorum. Bunu "seçili", vurgulanan vb. Gibi herhangi bir özel hücre özelliğini kullanarak çözmeye çalışmak, bana yardımcı olmadı ve bu yüzden aşağıda verilen çözümle geldim ve bu benim için çalıştı.

Aşama 1:

Seçili dizini saklamak için collectionView'da bir değişken oluşturun, burada selectedIndex adında bir sınıf düzeyi değişkeni kullandım

- (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];

}

-anoop


6
2018-05-08 05:42





Özel hücrenizde genel yöntem oluşturun:

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

Ayrıca -prepareForReuse hücre yönteminin yeniden tanımını yazınız:

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

Ve ViewController'ınızda, -didSelectItemAtIndexPath içinde tanımlanmış ve -didDeselectItemAtIndexPath içinde nullified olan _selectedIndexPath değişkenine sahip olmalısınız.

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;
}

2
2017-07-11 09:34





Bir tek @stefanB iOS 9.3'te çözüm benim için çalıştı

Burada değiştirmek zorunda olduğum şey Swift 2 için

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
 }

1
2018-04-26 08:48



Neden kullanmıyorsunuz collectionView(_:willDisplayCell:forItemAtIndexPath:) yerine? - eMdOS


Bunu çözmek için yaptığım şey, özelleştirilmiş hücrede değişiklik yapmaktı. Aradığınız özel bir hücren var. DataSetCell sınıfında aşağıdakileri yapabilirsiniz (kod hızlıdır)

override var isSelected: Bool {
    didSet {
        if isSelected {
            changeStuff
        } else {
            changeOtherStuff
        }
    }
}

Bu, hücrenin her seçildiğinde, seçili değilse, yeniden başlatıldığında veya yeniden kullanılabilir sıradan çağrıldığında, bu kodun çalışacağı ve değişikliklerin yapılacağıdır. Umarım bu size yardımcı olur.


1
2018-05-16 15:53





Hücrenin selectedBackgroundView öğesini backgroundColor = x olarak ayarlamanız yeterlidir.

Artık hücreye dokunduğunuz her seferinde seçili modu otomatik olarak değişecek ve x olarak değiştirmek için arka plan rengini kullanacaktır.


0
2017-07-20 16:00





Cevabınız için teşekkürler @RDC.

Aşağıdaki kodlar ile çalışır 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
}

0
2017-10-18 13:35





Hücrenin arka plan renkleri gibi hücre özelliklerinin değiştirilmesi UICollectionViewController'ın kendisinde yapılmamalıdır, bu sizin CollectionViewCell sınıfında yapılmalıdır. DidSelect ve didDeselect kullanmayın, sadece şunu kullanın:

class MyCollectionViewCell: UICollectionViewCell 
{
     override var isSelected: Bool
     {
         didSet
         {
            // Your code
         }
     } 
}

0
2018-04-09 01:42