我正在尝试子类化UICollectionViewLayoutAttributes
,以便我可以添加额外的属性 points (CGPoints
的数组)。
子类被设计为仅用作装饰视图的属性,因此我需要将成员representedElementCategory
设置为.Decoration
。但是representedElementCategory
是只读的,设置它的唯一方法是通过便利初始化器:
convenience init(forDecorationViewOfKind decorationViewKind: String, withIndexPath indexPath: NSIndexPath)
查看Objective-C标头我看到这个便利初始化器实际上被定义为工厂方法:
+ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath*)indexPath;
我希望我的子类'initialiser看起来像:
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!'演员会失败....
答案 0 :(得分:10)
事实证明,一个子类可以调用一个超类的便利初始化器,它可以反过来调用子类的初始化器。例如:
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
}
答案 1 :(得分:4)
UICollectionViewLayoutAttributes子类化需要一些诡计。 你有没有在https://developer.apple.com/library/ios/documentation/UIKit/Reference/UICollectionViewLayoutAttributes_class/
检查子类在大多数情况下,您按原样使用此类。如果要使用自定义布局属性补充基本布局属性,则可以子类化并定义要存储其他布局数据的任何属性。因为可以通过集合视图复制布局属性对象,所以通过实现适合将自定义属性复制到子类的新实例的任何方法,确保子类符合NSCopying协议。除了定义子类之外,您的UICollectionReusableView对象还需要实现applyLayoutAttributes:方法,以便它们可以在布局时应用任何自定义属性。
如果您子类化并实现任何自定义布局属性,则还必须覆盖继承的isEqual:方法以比较属性的值。在iOS 7及更高版本中,如果这些属性未更改,则集合视图不会应用布局属性。它通过使用isEqual:方法比较旧属性对象和新属性对象来确定属性是否已更改。由于此方法的默认实现仅检查此类的现有属性,因此必须实现自己的方法版本才能比较任何其他属性。如果您的自定义属性都相同,请调用super并在实现结束时返回结果值。
答案 2 :(得分:0)
方法名称已更改,因此转换为 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
}
}
}