如何防止uicollectionview的细胞重用

时间:2016-07-04 08:04:32

标签: ios swift uicollectionview

我使用 UICollectionView 并参考this link工具scroll table view Fixed single column and row,如下图所示。

scroll table

但是当我想添加shadow属性时,它会显示凌乱。

messy

我认为原因是我在渲染视觉视图时重用cell,但我不知道如何修复它:(

在下面提供我的代码,谢谢你的时间!

import Foundation
import SwiftyJSON


@objc(RNCollection)
class RNCollection : UICollectionView, UICollectionViewDataSource, UICollectionViewDelegate {

  var contentCellIdentifier = "CellIdentifier"
  var collectionView: UICollectionView!

  static var dataSource = []
  static var sections = 0
  static var rows = 0

  override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
    super.init(frame: CGRectZero, collectionViewLayout: RNCollectionLayout())

    self.registerClass(RNCollectionCell.self, forCellWithReuseIdentifier: contentCellIdentifier)
    self.directionalLockEnabled = false
    self.backgroundColor = UIColor.whiteColor()

    self.delegate = self
    self.dataSource = self

    self.frame = frame
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  func setConfig(config: String!) {
    var json: JSON = nil;
    if let data = config.dataUsingEncoding(NSUTF8StringEncoding) {
      json = JSON(data: data);
    };

    RNCollection.dataSource = json["dataSource"].arrayObject!
    RNCollection.sections = json["sections"].intValue
    RNCollection.rows = json["rows"].intValue
  }

  func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let contentCell: RNCollectionCell = collectionView.dequeueReusableCellWithReuseIdentifier(contentCellIdentifier, forIndexPath: indexPath) as! RNCollectionCell

    contentCell.textLabel.textColor = UIColor.blackColor()

    if indexPath.section == 0 {
      contentCell.backgroundColor = UIColor(red: 232/255.0, green: 232/255.0, blue: 232/255.0, alpha: 1.0)

      if indexPath.row == 0 {
        contentCell.textLabel.font = UIFont.systemFontOfSize(16)
        contentCell.textLabel.text = (RNCollection.dataSource[0] as! NSArray)[0] as? String
      } else {
        contentCell.textLabel.font = UIFont.systemFontOfSize(14)
        contentCell.textLabel.text = (RNCollection.dataSource[0] as! NSArray)[indexPath.row] as? String
      }
    } else {
      contentCell.textLabel.font = UIFont.systemFontOfSize(12)
      contentCell.backgroundColor = UIColor.whiteColor()

      if(indexPath.section % 2 == 0) {
        contentCell.backgroundColor = UIColor(red: 234/255.0, green: 234/255.0, blue: 236/255.0, alpha: 1.0)
      }

      if indexPath.row == 0 {
        contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[0] as? String
        contentCell.layer.shadowOffset = CGSize(width: 3, height: 3)
        contentCell.layer.shadowOpacity = 0.7
        contentCell.layer.shadowRadius = 2
      } else {
        contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[indexPath.row] as? String
      }
    }

    return contentCell
  }

  func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return RNCollection.rows
  }

  // MARK - UICollectionViewDataSource
  func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
    return RNCollection.sections
  }

}

4 个答案:

答案 0 :(得分:3)

您要为某个部分/行指定自定义项,而在其他情况下,您只需设置文本。您应该在其他条件中指定所需/默认自定义。考虑一下代码的这一部分

  if indexPath.row == 0 {
    contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[0] as? String
    contentCell.layer.shadowOffset = CGSize(width: 3, height: 3)
    contentCell.layer.shadowOpacity = 0.7
    contentCell.layer.shadowRadius = 2
  } else {
    contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[indexPath.row] as? String
  }

您已在if条件中指定了shadowOffsetshadowOpacityshadowRadius,但在其他情况下忽略了它们。如果在else条件中指定外观,则不会出现您现在面临的问题。它应该看起来像这样

  if indexPath.row == 0 {
    contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[0] as? String
    contentCell.layer.shadowOffset = CGSize(width: 3, height: 3)
    contentCell.layer.shadowOpacity = 0.7
    contentCell.layer.shadowRadius = 2
  } else {
    contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[indexPath.row] as? String
contentCell.layer.shadowOffset = 0
    contentCell.layer.shadowOpacity = 0
    contentCell.layer.shadowRadius = 0
  }

如果在所有条件检查中正确重置所有内容,则不会出现此问题。

答案 1 :(得分:2)

当你的行等于0时设置阴影:

if indexPath.row == 0 {...}

但是如果行不等于零,则集合视图可以在已设置阴影时重用该单元格。解决方案是在行不为0时重置阴影,在你的代码中你可以做这样的事情(参见todo):

    if indexPath.row == 0 { // Set up shadow here
        contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[0] as? String
        contentCell.layer.shadowOffset = CGSize(width: 3, height: 3)
        contentCell.layer.shadowOpacity = 0.7
        contentCell.layer.shadowRadius = 2
      } else {
        contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[indexPath.row] as? String
        //TODO: Remove the shadow here
      }

答案 2 :(得分:0)

如果您希望每次出现单元格时都保存单元格设置,则应设置方法的所有可能条件" func collectionView(collectionView:UICollectionView,cellForItemAtIndexPath indexPath:NSIndexPath) - > UICollectionViewCell"。仅当您的数据或项目很少时才禁止重复使用collectionView。

答案 3 :(得分:0)

在Objective-C中,但在Swift中,逻辑应该是相同的,而不是很难翻译。

RNCollectionCell

//These enums may have a better nam, I agree
typedef enum : NSUInteger {
    RNCollectionCellStyleColumnTitle,
    RNCollectionCellStyleColumnValue,
    RNCollectionCellStyleRowTitle,
    RNCollectionCellStyleUpperLeftCorner,
} RNCollectionCellStyle;

-(void)titleIt:(NSString *)title forStyle:(RNCollectionCellStyle)style forSection:(NSUInteger)section
{
    self.textLabel.textColor = [UIColor blackColor]; //Since it's always the same could be done elsewhere once for all.

    //Note I didn't check completely if the case were good, and I didn't add the background color logic, but it should be done here too.
    switch (style)
    {
        case RNCollectionCellStyleColumnTitle:
        {
            self.textLabel.font = [UIFont systemFontOfSize:12];
            self.layer.shadowOffset = CGSizeMake(3, 3);
            self.layer.shadowOpacity = 0.7;
            self.layer.shadowRadius = 2;
        }
            break;
        case RNCollectionCellStyleColumnValue:
        {
            self.textLabel.font = [UIFont systemFontOfSize:12];
            self.layer.shadowOffset = CGSizeZero;
            self.layer.shadowOpacity = 0;
            self.layer.shadowRadius = 0;
        }
            break;
        case RNCollectionCellStyleRowTitle:
        {
            self.textLabel.font = [UIFont systemFontOfSize:14];
            self.layer.shadowOffset = CGSizeZero;
            self.layer.shadowOpacity = 0;
            self.layer.shadowRadius = 0;
        }
            break;
        case RNCollectionCellStyleUpperLeftCorner:
        {
            self.textLabel.font = [UIFont systemFontOfSize:16];
            self.layer.shadowOffset = CGSizeZero;
            self.layer.shadowOpacity = 0;
            self.layer.shadowRadius = 0;
        }
            break;
        default:
            break;
    }

    self.textLabel.text = title;

}

-(void)prepareForReuse
{
    [super prepareForReuse];
    self.layer.shadowOffset = CGSizeZero;
    self.layer.shadowOpacity = 0;
    self.layer.shadowRadius = 0;
}

RNCollection

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
    RNCollectionCell *contentCell = [collectionView dequeueReusableCellWithReuseIdentifier: contentCellIdentifier forIndexPath:indexPath];

    //Here check what style you need to do
    //Also, you seems to always do dataSource[indexPath.section][indexPath.row], you just use the "if test values".
    [contentCell titleIt:dataSource[indexPath.section][indexPath.row]
                forStyle:RNCollectionCellStyleColumnTitle
              forSection:[indexPath section]];

    return contentCell;
}

如上所述,我没有根据您的需要检查所有案例是否正确。 但是,你没有“防止重复使用细胞”,它已经过优化。 在重新使用或设置值之前,需要“重置”值。从理论上讲,在prepareForReuse中完成的事情应该足够了,你不应该在switch中“重置”图层效果,但老实说我没有检查它。