嵌入容器视图时,UICollectionViewController 重新排序不起作用
UICollectionViewController reordering does not work when embedded in a container view
当我将其添加到我的 UICollectionViewController
子类时,iOS9 正在重新排序
override func collectionView(collectionView: UICollectionView,
moveItemAtIndexPath sourceIndexPath: NSIndexPath,
toIndexPath destinationIndexPath: NSIndexPath)
当此 UICollectionViewController
子类嵌入到容器视图中时,它不起作用。
我已经对问题做了演示here
关于为什么或如何解决它的任何想法?
这里的问题是您将 UICollectionView 放在了位于 UIViewController 中的 UIContainerView 中。这只需要再执行几个步骤,UICollectionView 就能按预期工作。
将以下内容添加到 CollectionViewController 中的 ViewDidLoad:
self.collectionView!.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: "handleLongGesture:"))
然后将以下函数添加到您的 CollectionViewController 中:
func handleLongGesture(gesture: UILongPressGestureRecognizer)
{
switch(gesture.state)
{
case UIGestureRecognizerState.Began:
guard let selectedIndexPath = self.collectionView!.indexPathForItemAtPoint(gesture.locationInView(self.collectionView)) else
{
break
}
collectionView!.beginInteractiveMovementForItemAtIndexPath(selectedIndexPath)
case UIGestureRecognizerState.Changed:
collectionView!.updateInteractiveMovementTargetPosition(gesture.locationInView(gesture.view!))
case UIGestureRecognizerState.Ended:
collectionView!.endInteractiveMovement()
default:
collectionView!.cancelInteractiveMovement()
}
}
最后确保包含以下内容以确保正确处理数据源:
override func collectionView(collectionView: UICollectionView, moveItemAtIndexPath sourceIndexPath: NSIndexPath,toIndexPath destinationIndexPath: NSIndexPath) {
// Swap the values of the source and destination
}
查看此 link 了解更多信息。
希望这对您有所帮助。
Scooter 的答案是正确的!
这是 Swift 3 语法版本:
import UIKit
class ViewController: UIViewController
{
// MARK: - IBOutlets
@IBOutlet weak var uiCollectionView: UICollectionView!
// MARK: - Lifecycle
override func viewDidLoad()
{
super.viewDidLoad()
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.handleLongGesture))
self.uiCollectionView.addGestureRecognizer(longPressGesture)
}
// MARK: - Gesture recogniser
@objc func handleLongGesture(gesture: UILongPressGestureRecognizer)
{
switch(gesture.state)
{
case .began:
guard let selectedIndexPath = self.uiCollectionView.indexPathForItem(at: gesture.location(in: self.uiCollectionView)) else
{
break
}
self.uiCollectionView.beginInteractiveMovementForItem(at: selectedIndexPath)
case .changed:
self.uiCollectionView.updateInteractiveMovementTargetPosition(gesture.location(in: gesture.view!))
case .ended:
self.uiCollectionView.endInteractiveMovement()
default:
self.uiCollectionView.cancelInteractiveMovement()
}
}
}
// MARK: - UICollectionViewDataSource
extension ViewController: UICollectionViewDataSource
{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
// TODO: Link to your data model
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
// TODO: Link to your data model
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView,
moveItemAt sourceIndexPath: IndexPath,
to destinationIndexPath: IndexPath)
{
// TODO: Update your data model to reflect the change
}
}
// MARK: - UICollectionViewDelegate
extension ViewController: UICollectionViewDelegate
{
// TODO: Add any UICollectionViewDelegate here if needed.
}
请注意,此代码不考虑触摸位置偏移 - 因此当您开始拖动时,您的单元格将 'jump' 在您的手指下方居中。如果你想防止这种情况发生,那么你需要在 UIViewController
中定义一个 CGPoint
属性(在下面的代码中命名为 initialGestureLocationInCell
)。然后用这个替换初始示例:
[...]
case .began:
guard let selectedIndexPath = self.uiCollectionView.indexPathForItem(at: gesture.location(in: self.uiCollectionView)) else
{
break
}
let selectedCell = self.uiCollectionView.cellForItem(at: selectedIndexPath)!
let gestureLocationInCell_RelativeToOrigin = gesture.location(in: selectedCell)
let gestureLocationInCell_RelativeToCentre = CGPoint(x: gestureLocationInCell_RelativeToOrigin.x - selectedCell.frame.size.width/2,
y: gestureLocationInCell_RelativeToOrigin.y - selectedCell.frame.size.height/2)
self.initialGestureLocationInCell = gestureLocationInCell_RelativeToCentre
self.uiCollectionView.beginInteractiveMovementForItem(at: selectedIndexPath)
case .changed:
let gestureLocationInCollectionView = gesture.location(in: gesture.view!)
let targetPosition = CGPoint(x: gestureLocationInCollectionView.x - self.initialGestureLocationInCell.x,
y: gestureLocationInCollectionView.y - self.initialGestureLocationInCell.y)
self.uiCollectionView.updateInteractiveMovementTargetPosition(targetPosition)
[...]
UICollectionViewController 在嵌入到容器视图中时不会安装它的 re-ordering 手势识别器,因为 installsStandardGestureForInteractiveMovement 设置为 false。目前尚不清楚这是故意的还是错误。
一个work-around:
在嵌入式 UICollectionViewControllers 的 viewDidAppear(或生命周期的稍后部分)中将 installsStandardGestureForInteractiveMovement 设置为 true:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.installsStandardGestureForInteractiveMovement = true
}
重新排序与 non-embedded UICollectionViewController 的工作方式相同。数据源只需要声明
func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)
请注意,您需要将 collectionView 的 clipsToBounds 设置为 false,以便在将单元格拖出集合视图时能够看到这些单元格。但是,这意味着滚动到边界外的单元格也将可见,这可能不可行,具体取决于您的设计。
当我将其添加到我的 UICollectionViewController
子类时,iOS9 正在重新排序
override func collectionView(collectionView: UICollectionView,
moveItemAtIndexPath sourceIndexPath: NSIndexPath,
toIndexPath destinationIndexPath: NSIndexPath)
当此 UICollectionViewController
子类嵌入到容器视图中时,它不起作用。
我已经对问题做了演示here
关于为什么或如何解决它的任何想法?
这里的问题是您将 UICollectionView 放在了位于 UIViewController 中的 UIContainerView 中。这只需要再执行几个步骤,UICollectionView 就能按预期工作。
将以下内容添加到 CollectionViewController 中的 ViewDidLoad:
self.collectionView!.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: "handleLongGesture:"))
然后将以下函数添加到您的 CollectionViewController 中:
func handleLongGesture(gesture: UILongPressGestureRecognizer)
{
switch(gesture.state)
{
case UIGestureRecognizerState.Began:
guard let selectedIndexPath = self.collectionView!.indexPathForItemAtPoint(gesture.locationInView(self.collectionView)) else
{
break
}
collectionView!.beginInteractiveMovementForItemAtIndexPath(selectedIndexPath)
case UIGestureRecognizerState.Changed:
collectionView!.updateInteractiveMovementTargetPosition(gesture.locationInView(gesture.view!))
case UIGestureRecognizerState.Ended:
collectionView!.endInteractiveMovement()
default:
collectionView!.cancelInteractiveMovement()
}
}
最后确保包含以下内容以确保正确处理数据源:
override func collectionView(collectionView: UICollectionView, moveItemAtIndexPath sourceIndexPath: NSIndexPath,toIndexPath destinationIndexPath: NSIndexPath) {
// Swap the values of the source and destination
}
查看此 link 了解更多信息。
希望这对您有所帮助。
Scooter 的答案是正确的! 这是 Swift 3 语法版本:
import UIKit
class ViewController: UIViewController
{
// MARK: - IBOutlets
@IBOutlet weak var uiCollectionView: UICollectionView!
// MARK: - Lifecycle
override func viewDidLoad()
{
super.viewDidLoad()
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.handleLongGesture))
self.uiCollectionView.addGestureRecognizer(longPressGesture)
}
// MARK: - Gesture recogniser
@objc func handleLongGesture(gesture: UILongPressGestureRecognizer)
{
switch(gesture.state)
{
case .began:
guard let selectedIndexPath = self.uiCollectionView.indexPathForItem(at: gesture.location(in: self.uiCollectionView)) else
{
break
}
self.uiCollectionView.beginInteractiveMovementForItem(at: selectedIndexPath)
case .changed:
self.uiCollectionView.updateInteractiveMovementTargetPosition(gesture.location(in: gesture.view!))
case .ended:
self.uiCollectionView.endInteractiveMovement()
default:
self.uiCollectionView.cancelInteractiveMovement()
}
}
}
// MARK: - UICollectionViewDataSource
extension ViewController: UICollectionViewDataSource
{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
// TODO: Link to your data model
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
// TODO: Link to your data model
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView,
moveItemAt sourceIndexPath: IndexPath,
to destinationIndexPath: IndexPath)
{
// TODO: Update your data model to reflect the change
}
}
// MARK: - UICollectionViewDelegate
extension ViewController: UICollectionViewDelegate
{
// TODO: Add any UICollectionViewDelegate here if needed.
}
请注意,此代码不考虑触摸位置偏移 - 因此当您开始拖动时,您的单元格将 'jump' 在您的手指下方居中。如果你想防止这种情况发生,那么你需要在 UIViewController
中定义一个 CGPoint
属性(在下面的代码中命名为 initialGestureLocationInCell
)。然后用这个替换初始示例:
[...]
case .began:
guard let selectedIndexPath = self.uiCollectionView.indexPathForItem(at: gesture.location(in: self.uiCollectionView)) else
{
break
}
let selectedCell = self.uiCollectionView.cellForItem(at: selectedIndexPath)!
let gestureLocationInCell_RelativeToOrigin = gesture.location(in: selectedCell)
let gestureLocationInCell_RelativeToCentre = CGPoint(x: gestureLocationInCell_RelativeToOrigin.x - selectedCell.frame.size.width/2,
y: gestureLocationInCell_RelativeToOrigin.y - selectedCell.frame.size.height/2)
self.initialGestureLocationInCell = gestureLocationInCell_RelativeToCentre
self.uiCollectionView.beginInteractiveMovementForItem(at: selectedIndexPath)
case .changed:
let gestureLocationInCollectionView = gesture.location(in: gesture.view!)
let targetPosition = CGPoint(x: gestureLocationInCollectionView.x - self.initialGestureLocationInCell.x,
y: gestureLocationInCollectionView.y - self.initialGestureLocationInCell.y)
self.uiCollectionView.updateInteractiveMovementTargetPosition(targetPosition)
[...]
UICollectionViewController 在嵌入到容器视图中时不会安装它的 re-ordering 手势识别器,因为 installsStandardGestureForInteractiveMovement 设置为 false。目前尚不清楚这是故意的还是错误。
一个work-around:
在嵌入式 UICollectionViewControllers 的 viewDidAppear(或生命周期的稍后部分)中将 installsStandardGestureForInteractiveMovement 设置为 true:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.installsStandardGestureForInteractiveMovement = true
}
重新排序与 non-embedded UICollectionViewController 的工作方式相同。数据源只需要声明
func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)
请注意,您需要将 collectionView 的 clipsToBounds 设置为 false,以便在将单元格拖出集合视图时能够看到这些单元格。但是,这意味着滚动到边界外的单元格也将可见,这可能不可行,具体取决于您的设计。