【问题标题】:UICollectionViewController reordering does not work when embedded in a container view嵌入到容器视图中时,UICollectionViewController 重新排序不起作用
【发布时间】:2016-05-12 00:48:24
【问题描述】:

当我将它添加到我的UICollectionViewController 子类时,iOS9 中的重新排序工作正常

override func collectionView(collectionView: UICollectionView, 
        moveItemAtIndexPath sourceIndexPath: NSIndexPath, 
           toIndexPath destinationIndexPath: NSIndexPath)

当这个 UICollectionViewController 子类嵌入到容器视图中时,它不起作用。

我已经做了一个问题的演示here

关于为什么或如何解决它的任何想法?

【问题讨论】:

  • 用@Scooter here的解决方案更新示例

标签: ios swift uicollectionview ios9


【解决方案1】:

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.
}

请注意,此代码不考虑触摸位置偏移 - 因此当您开始拖动时,您的单元格将“跳跃”到您手指下方的中心。如果你想防止这种情况发生,那么你需要在你的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)
[...]

【讨论】:

  • 第二部分真的很有用!谢谢。
  • 非常感谢您关于触摸位置偏移的建议。
  • 你摇滚
【解决方案2】:

这里的问题是您将 UICollectionView 放在了 UIContainerView 中,而该 UIContainerView 位于 UIViewController 中。只需再执行几个步骤,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 了解更多信息。

希望这对您有所帮助。

【讨论】:

  • 这很好,但是有什么方法可以加快手势识别器的速度吗?我只是发现需要太长时间才能注意到。谢谢。
  • @Supertecnoboff 是的,您可以在将手势添加到集合视图之前更改手势的 .minimumPressDuration 属性。
【解决方案3】:

UICollectionViewController 在嵌入容器视图时不会安装它的重新排序手势识别器,因为 installsStandardGestureForInteractiveMovement 设置为 false。目前尚不清楚这是故意的还是错误的。

一种解决方法:

在 viewDidAppear(或生命周期后期)中为嵌入式 UICollectionViewController 设置 installsStandardGestureForInteractiveMovement 为 true:

override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.installsStandardGestureForInteractiveMovement = true
    }

重新排序的工作方式与非嵌入式 UICollectionViewController 相同。数据源只需要声明

func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)

请注意,您需要将 collectionView 的 clipsToBounds 设置为 false,以便在将单元格拖到集合视图之外时能够看到这些单元格。但是,这意味着滚动到边界之外的单元格也将可见,这取决于您的设计可能不可行。

【讨论】:

    猜你喜欢
    • 2016-12-10
    • 2015-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-20
    相关资源
    最近更新 更多