【问题标题】:How to subclass UICollectionViewLayoutAttributes如何继承 UICollectionViewLayoutAttributes
【发布时间】:2015-07-22 22:30:16
【问题描述】:

我正在尝试继承 UICollectionViewLayoutAttributes 以便我可以添加一个额外的属性 pointsCGPoints 的数组)。

子类设计为仅用作装饰视图的属性,因此我需要将成员representedElementCategory 设置为.Decoration。但是representedElementCategory 是只读的,设置它的唯一方法是通过便利的初始化程序:

convenience init(forDecorationViewOfKind decorationViewKind: String, withIndexPath indexPath: NSIndexPath)

查看 Objective-C 头文件,我看到这个便利初始化器实际上被定义为工厂方法:

+ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath*)indexPath;

我希望我的子类的初始化器看起来像:

CustomLayoutAttributes(points: [CGPoint], representedElementKind: String, withIndexPath: NSIndexPath) 

但是由于子类不能调用它们父母的便利初始化器,我看不出这是怎么可能的。

我认为子类化的唯一方法是正确的:

class CustomLayoutAttributes: UICollectionViewLayoutAttributes {
   var points = [CGPoint]()
}

let attribs = UICollectionViewLayoutAttributes(
     forDecorationViewOfKind: "x", 
     withIndexPath: NSIndexPath(forItem: 0, inSection: 0)
) as! CustomLayoutAttributes
attribs.points = [CGPoint(x: 1.0, y: 2.0), CGPoint(x: 4.0, y: 5.0)]

实际上这行不通,因为 'as!'演员会失败....

【问题讨论】:

  • 我应该补充一点,我在自定义 UICollectionViewLayout 中使用这些布局属性,它需要能够创建它们,因此是问题。

标签: ios objective-c swift uicollectionview uicollectionviewlayout


【解决方案1】:

事实证明,子类可以调用超类的便利初始化程序,而超类又可以调用子类的初始化程序。例如:

CustomLayoutAttributes(forDecorationViewOfKind: "decoration1", withIndexPath: indexPath)

这里: init(forDecorationViewOfKind: String, withIndexPath: NSIndexPath) 未在 CustomLayoutAttributes 类中定义,但仍可用于构造子类的实例。

实现示例:

// CustomLayoutAttributes.swift

class CustomLayoutAttributes: UICollectionViewLayoutAttributes {

   // Additional attribute to test our custom layout
   var points = [CGPoint]()

   // MARK: NSCopying
   override func copyWithZone(zone: NSZone) -> AnyObject {

      let copy = super.copyWithZone(zone) as! CustomLayoutAttributes
      copy.points = self.points
      return copy
   }

    override func isEqual(object: AnyObject?) -> Bool {

      if let rhs = object as? CustomLayoutAttributes {
         if points != rhs.points {
            return false
         }
         return super.isEqual(object)
      } else {
         return false
      }
   }
}

// CustomLayout.swift

override func layoutAttributesForItemAtIndexPath(path: NSIndexPath) -> UICollectionViewLayoutAttributes? {  


    let attributes = CustomLayoutAttributes(forDecorationViewOfKind: "decoration1", withIndexPath: indexPath)
    attributes.points = [...]

    return attributes  
}

【讨论】:

  • 如果您还继承了UICollectionViewLayout,请不要忘记在您的子类中覆盖layoutAttributesClass 以返回您的自定义属性的Class
【解决方案2】:

UICollectionViewLayoutAttributes 子类化需要一些特殊性。 你有没有检查子类不在https://developer.apple.com/library/ios/documentation/UIKit/Reference/UICollectionViewLayoutAttributes_class/

在大多数情况下,您按原样使用此类。如果您想用自定义布局属性补充基本布局属性,您可以子类化并定义要存储附加布局数据的任何属性。因为布局属性对象可能被集合视图复制,所以通过实现任何适合将自定义属性复制到子类的新实例的方法来确保您的子类符合 NSCopying 协议。除了定义您的子类之外,您的 UICollectionReusableView 对象还需要实现 applyLayoutAttributes: 方法,以便它们可以在布局时应用任何自定义属性。

如果您继承并实现任何自定义布局属性,您还必须重写继承的 isEqual: 方法来比较您的属性值。在 iOS 7 及更高版本中,如果这些属性未更改,则集合视图不会应用布局属性。它通过使用 isEqual: 方法比较新旧属性对象来确定属性是否已更改。由于此方法的默认实现仅检查此类的现有属性,因此您必须实现您自己的方法版本才能比较任何其他属性。如果您的自定义属性都相等,请调用 super 并在实现结束时返回结果值。

【讨论】:

  • 是的,谢谢,但我不明白这如何回答我的问题。
  • 好的,所以这可能与 layoutAttributesClass 不是在 UICollectionViewLayout 类上定义而是在它的扩展上定义的事实有关。这可能与此未答复有关
【解决方案3】:

方法名称已更改,因此转换为 Swift 5

    class SceneSelectorAttributes: UICollectionViewLayoutAttributes {

    var value = CGFloat()

    override func copy(with zone: NSZone? = nil) -> Any {
        let copy = super.copy(with: zone) as! SceneSelectorAttributes
        copy.value = self.value
        return copy
    }

    override func isEqual(_ object: Any?) -> Bool {
        if let rhs = object as? SceneSelectorAttributes {
            if value != rhs.value {
                return false
            }
            return super.isEqual(object)
        } else {
            return false
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-25
    • 2017-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多