将 SpringyCollectionView 转换为 Swift
Converting SpringyCollectionView to Swift
我正在尝试将以下 FLowLayout 从 Objective C 转换为 Swift 3。不幸的是我得到一个空错误。有人已经实现了类似的代码或将此代码转换为 Swift 3 吗? Springy Collection View Library
这是我目前得到的:
override func prepare() {
super.prepare()
// Need to overflow our actual visible rect slightly to avoid flickering.
let visibleRect = self.collectionView!.bounds.insetBy(dx: -100, dy: -100)
let itemsInVisibleRectArray: NSArray = super.layoutAttributesForElements(in: visibleRect)! as NSArray
let itemsIndexPathsInVisibleRectSet: NSSet = NSSet(array: itemsInVisibleRectArray.value(forKey: "indexPath") as! [AnyObject])
// Step 1: Remove any behaviours that are no longer visible.
let noLongerVisibleBehaviours = (self.dynamicAnimator.behaviors as NSArray).filtered(using: NSPredicate(block: {behaviour, bindings in
let currentlyVisible: Bool = itemsIndexPathsInVisibleRectSet.member((behaviour as! UIAttachmentBehavior).items.first!) != nil
return !currentlyVisible
}))
for (_, obj) in noLongerVisibleBehaviours.enumerated() {
self.dynamicAnimator.removeBehavior(obj as! UIDynamicBehavior)
self.visibleIndexPathsSet.remove((obj as! UIAttachmentBehavior).items.first!)
}
// Step 2: Add any newly visible behaviours.
// A "newly visible" item is one that is in the itemsInVisibleRect(Set|Array) but not in the visibleIndexPathsSet
let newlyVisibleItems = itemsInVisibleRectArray.filtered(using: NSPredicate(block: {item, bindings in
let currentlyVisible: Bool = self.visibleIndexPathsSet.member(item!) != nil
return !currentlyVisible
}))
let touchLocation: CGPoint = self.collectionView!.panGestureRecognizer.location(in: self.collectionView)
for (_, item) in newlyVisibleItems.enumerated() {
let springBehaviour: UIAttachmentBehavior = UIAttachmentBehavior(item: item as! UIDynamicItem, attachedToAnchor: (item as AnyObject).center)
springBehaviour.length = CGFloat(kLength)
springBehaviour.damping = CGFloat(kDamping)
springBehaviour.frequency = CGFloat(kFrequence)
let zeropoint = CGPoint(x: 0,y :0)
// If our touchLocation is not (0,0), we'll need to adjust our item's center "in flight"
if (!zeropoint.equalTo(touchLocation)) {
let yDistanceFromTouch = fabsf(Float(touchLocation.y - springBehaviour.anchorPoint.y))
let xDistanceFromTouch = fabsf(Float(touchLocation.x - springBehaviour.anchorPoint.x))
let scrollResistance = (yDistanceFromTouch + xDistanceFromTouch) / Float(kResistence)
let item = springBehaviour.items.first as! UICollectionViewLayoutAttributes
var center = item.center
if self.latestDelta < 0 {
center.x += max(self.latestDelta, self.latestDelta * CGFloat(scrollResistance))
} else {
center.x += min(self.latestDelta, self.latestDelta * CGFloat(scrollResistance))
}
item.center = center
}
self.dynamicAnimator.addBehavior(springBehaviour)
self.visibleIndexPathsSet.add(item)
}
}
我在这里得到第一个错误:
最好使用原生 swift 类型。类似于:
override func prepare()
{
super.prepare()
let visibleRect = CGRect(origin: self.collectionView?.bounds.origin ?? CGPoint.zero, size: self.collectionView?.frame.size ?? CGSize.zero).insetBy(dx: -100, dy: -100)
let itemsInVisibleRectArray = super.layoutAttributesForElements(in: visibleRect) ?? []
let itemsIndexPathsInVisibleRectSet = Set(itemsInVisibleRectArray.map{ [=10=].indexPath })
let noLongerVisibleBehaviors = self.dynamicAnimator.behaviors.filter
{ behavior in
guard let behavior = behavior as? UIAttachmentBehavior else { return false }
guard let attribute = behavior.items.first as? UICollectionViewLayoutAttributes else { return false }
let currentlyVisible = itemsIndexPathsInVisibleRectSet.contains(attribute.indexPath)
return !currentlyVisible
}
noLongerVisibleBehaviors.forEach
{ behavior in
self.dynamicAnimator.removeBehavior(behavior)
guard let behavior = behavior as? UIAttachmentBehavior else { return }
guard let attribute = behavior.items.first as? UICollectionViewLayoutAttributes else { return }
self.visibleIndexPathsSet.remove(attribute.indexPath)
}
let newlyVisibleItems = itemsInVisibleRectArray.filter
{ item in
let currentlyVisible = self.visibleIndexPathsSet.contains(item.indexPath)
return !currentlyVisible
}
let touchLocation = self.collectionView?.panGestureRecognizer.location(in: self.collectionView)
newlyVisibleItems.forEach
{ item in
var center = item.center
let springBehavior = UIAttachmentBehavior(item: item, attachedToAnchor: center)
springBehavior.length = 0.0
springBehavior.damping = 0.8
springBehavior.frequency = 1.0
if CGPoint.zero != touchLocation
{
let yDistanceFromTouch = fabs(touchLocation?.y ?? 0 - springBehavior.anchorPoint.y)
let xDistanceFromTouch = fabs(touchLocation?.x ?? 0 - springBehavior.anchorPoint.x)
let scrollResistance = (yDistanceFromTouch + xDistanceFromTouch) / 1500.0
if self.latestDelta < 0.0
{
center.y += max(self.latestDelta, self.latestDelta * scrollResistance)
}
else
{
center.y += min(self.latestDelta, self.latestDelta * scrollResistance)
}
item.center = center
}
self.dynamicAnimator.addBehavior(springBehavior)
self.visibleIndexPathsSet.insert(item.indexPath)
}
}
使用 NSArray
和 NSPredicate
不是静态类型的,容易出现运行时错误,并且全方位不是很 swifty。
spring 效果对我有用。
你可以看到所有的代码here.也许它比你想象的更微妙。
我正在尝试将以下 FLowLayout 从 Objective C 转换为 Swift 3。不幸的是我得到一个空错误。有人已经实现了类似的代码或将此代码转换为 Swift 3 吗? Springy Collection View Library
这是我目前得到的:
override func prepare() {
super.prepare()
// Need to overflow our actual visible rect slightly to avoid flickering.
let visibleRect = self.collectionView!.bounds.insetBy(dx: -100, dy: -100)
let itemsInVisibleRectArray: NSArray = super.layoutAttributesForElements(in: visibleRect)! as NSArray
let itemsIndexPathsInVisibleRectSet: NSSet = NSSet(array: itemsInVisibleRectArray.value(forKey: "indexPath") as! [AnyObject])
// Step 1: Remove any behaviours that are no longer visible.
let noLongerVisibleBehaviours = (self.dynamicAnimator.behaviors as NSArray).filtered(using: NSPredicate(block: {behaviour, bindings in
let currentlyVisible: Bool = itemsIndexPathsInVisibleRectSet.member((behaviour as! UIAttachmentBehavior).items.first!) != nil
return !currentlyVisible
}))
for (_, obj) in noLongerVisibleBehaviours.enumerated() {
self.dynamicAnimator.removeBehavior(obj as! UIDynamicBehavior)
self.visibleIndexPathsSet.remove((obj as! UIAttachmentBehavior).items.first!)
}
// Step 2: Add any newly visible behaviours.
// A "newly visible" item is one that is in the itemsInVisibleRect(Set|Array) but not in the visibleIndexPathsSet
let newlyVisibleItems = itemsInVisibleRectArray.filtered(using: NSPredicate(block: {item, bindings in
let currentlyVisible: Bool = self.visibleIndexPathsSet.member(item!) != nil
return !currentlyVisible
}))
let touchLocation: CGPoint = self.collectionView!.panGestureRecognizer.location(in: self.collectionView)
for (_, item) in newlyVisibleItems.enumerated() {
let springBehaviour: UIAttachmentBehavior = UIAttachmentBehavior(item: item as! UIDynamicItem, attachedToAnchor: (item as AnyObject).center)
springBehaviour.length = CGFloat(kLength)
springBehaviour.damping = CGFloat(kDamping)
springBehaviour.frequency = CGFloat(kFrequence)
let zeropoint = CGPoint(x: 0,y :0)
// If our touchLocation is not (0,0), we'll need to adjust our item's center "in flight"
if (!zeropoint.equalTo(touchLocation)) {
let yDistanceFromTouch = fabsf(Float(touchLocation.y - springBehaviour.anchorPoint.y))
let xDistanceFromTouch = fabsf(Float(touchLocation.x - springBehaviour.anchorPoint.x))
let scrollResistance = (yDistanceFromTouch + xDistanceFromTouch) / Float(kResistence)
let item = springBehaviour.items.first as! UICollectionViewLayoutAttributes
var center = item.center
if self.latestDelta < 0 {
center.x += max(self.latestDelta, self.latestDelta * CGFloat(scrollResistance))
} else {
center.x += min(self.latestDelta, self.latestDelta * CGFloat(scrollResistance))
}
item.center = center
}
self.dynamicAnimator.addBehavior(springBehaviour)
self.visibleIndexPathsSet.add(item)
}
}
我在这里得到第一个错误:
最好使用原生 swift 类型。类似于:
override func prepare()
{
super.prepare()
let visibleRect = CGRect(origin: self.collectionView?.bounds.origin ?? CGPoint.zero, size: self.collectionView?.frame.size ?? CGSize.zero).insetBy(dx: -100, dy: -100)
let itemsInVisibleRectArray = super.layoutAttributesForElements(in: visibleRect) ?? []
let itemsIndexPathsInVisibleRectSet = Set(itemsInVisibleRectArray.map{ [=10=].indexPath })
let noLongerVisibleBehaviors = self.dynamicAnimator.behaviors.filter
{ behavior in
guard let behavior = behavior as? UIAttachmentBehavior else { return false }
guard let attribute = behavior.items.first as? UICollectionViewLayoutAttributes else { return false }
let currentlyVisible = itemsIndexPathsInVisibleRectSet.contains(attribute.indexPath)
return !currentlyVisible
}
noLongerVisibleBehaviors.forEach
{ behavior in
self.dynamicAnimator.removeBehavior(behavior)
guard let behavior = behavior as? UIAttachmentBehavior else { return }
guard let attribute = behavior.items.first as? UICollectionViewLayoutAttributes else { return }
self.visibleIndexPathsSet.remove(attribute.indexPath)
}
let newlyVisibleItems = itemsInVisibleRectArray.filter
{ item in
let currentlyVisible = self.visibleIndexPathsSet.contains(item.indexPath)
return !currentlyVisible
}
let touchLocation = self.collectionView?.panGestureRecognizer.location(in: self.collectionView)
newlyVisibleItems.forEach
{ item in
var center = item.center
let springBehavior = UIAttachmentBehavior(item: item, attachedToAnchor: center)
springBehavior.length = 0.0
springBehavior.damping = 0.8
springBehavior.frequency = 1.0
if CGPoint.zero != touchLocation
{
let yDistanceFromTouch = fabs(touchLocation?.y ?? 0 - springBehavior.anchorPoint.y)
let xDistanceFromTouch = fabs(touchLocation?.x ?? 0 - springBehavior.anchorPoint.x)
let scrollResistance = (yDistanceFromTouch + xDistanceFromTouch) / 1500.0
if self.latestDelta < 0.0
{
center.y += max(self.latestDelta, self.latestDelta * scrollResistance)
}
else
{
center.y += min(self.latestDelta, self.latestDelta * scrollResistance)
}
item.center = center
}
self.dynamicAnimator.addBehavior(springBehavior)
self.visibleIndexPathsSet.insert(item.indexPath)
}
}
使用 NSArray
和 NSPredicate
不是静态类型的,容易出现运行时错误,并且全方位不是很 swifty。
spring 效果对我有用。
你可以看到所有的代码here.也许它比你想象的更微妙。