在集合视图中交换单元格时保持单元格旋转

时间:2017-10-29 18:24:21

标签: ios swift uicollectionview

我有一个3 x 3网格中有9个单元格的集合视图。我可以使用答案代码将单元格交换到这个问题 - Custom Cell Reorder Behavior in CollectionView,我也可以使用

旋转单元格

如果让indexPath = self.collectionView?.indexPathForItem(at:sender.location(in:self.collectionView)){

let cell = self.collectionView?.cellForItem(at: indexPath)

cell?.transform = (cell?.transform.rotated(by: _direction))!

}

当我旋转一个单元格然后将其与另一个单元格交换时,会出现问题。旋转重置,单元格在交换后恢复到原始位置(0度)。

我希望能够旋转细胞然后交换它们而不会失去它们的旋转。

编辑: 这是我在View Controller中的旋转功能以及用于交换单元格的handleLongGesture函数:

@IBAction func userSwippedRight(_ sender: UISwipeGestureRecognizer) {
    rotate(_direction: CGFloat(Double.pi / 2), sender: sender)
}

@IBAction func userSwippedLeft(_ sender: UISwipeGestureRecognizer) {
    rotate(_direction: CGFloat(-Double.pi / 2), sender: sender)
}

func rotate(_direction: CGFloat, sender: UISwipeGestureRecognizer ) {

UIView.animate(withDuration: 0.25) {
        if let indexPath = self.collectionView?.indexPathForItem(at: sender.location(in: self.collectionView)) {

            let cell = self.collectionView?.cellForItem(at: indexPath)

            cell?.transform = (cell?.transform.rotated(by: _direction))!


            let radians:Float = atan2f(Float(cell!.transform.b), Float(cell!.transform.a))
            var degrees:Int = Int(radians * Float(180 / Double.pi))

            if(degrees == -180)
            {
                degrees = 180
            }

            print(degrees)

        } else {
            print("Swipe Registered")

        }
    }   
}


func handleLongGesture(_ gesture: UILongPressGestureRecognizer) {

    switch(gesture.state) {

    case UIGestureRecognizerState.began:
        guard let selectedIndexPath = self.collectionView?.indexPathForItem(at: gesture.location(in: self.collectionView)) else {
            break
        }
        collectionView?.beginInteractiveMovementForItem(at: selectedIndexPath)
    case UIGestureRecognizerState.changed:
        collectionView?.updateInteractiveMovementTargetPosition(gesture.location(in: gesture.view!))
    case UIGestureRecognizerState.ended:
        collectionView?.endInteractiveMovement()
    default:
        collectionView?.cancelInteractiveMovement()
    }
}

然后下面是UICollectionView的子类,我在其中为单元格的交互式移动添加了自定义处理。

import UIKit

    extension UIView {
        func snapshot() -> UIImage {
            UIGraphicsBeginImageContext(self.bounds.size)
            self.layer.render(in: UIGraphicsGetCurrentContext()!)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return image!
        }
    }

    extension CGPoint {
        func distanceToPoint(p:CGPoint) -> CGFloat {
            return sqrt(pow((p.x - x), 2) + pow((p.y - y), 2))
        }
    }

    struct SwapDescription : Hashable {
        var firstItem : Int
        var secondItem : Int

        var hashValue: Int {
            get {
                return (firstItem * 10) + secondItem
            }
        }
    }

    func ==(lhs: SwapDescription, rhs: SwapDescription) -> Bool {
        return lhs.firstItem == rhs.firstItem && lhs.secondItem == rhs.secondItem
    }

    class SwappingCollectionView: UICollectionView {

        var interactiveCell = UICollectionViewCell()
        var myView : UICollectionView?
        var interactiveIndexPath : NSIndexPath?
        var interactiveView : UIView?
        var swapSet : Set<SwapDescription> = Set()
        var previousPoint : CGPoint?

        static let distanceDelta:CGFloat = 2 // adjust as needed


        override func beginInteractiveMovementForItem(at indexPath: IndexPath) -> Bool {

            self.interactiveIndexPath = indexPath as NSIndexPath?

            self.interactiveCell = self.cellForItem(at: indexPath as IndexPath) as! CustomCellCollectionViewCell

            self.interactiveCell.transform = CGAffineTransform(scaleX: 1.05, y: 1.05)

            self.interactiveView = UIImageView(image: self.interactiveCell.snapshot())

            self.interactiveView?.frame = self.interactiveCell.frame

            self.addSubview(self.interactiveView!)
            self.bringSubview(toFront: self.interactiveView!)

            self.interactiveCell.isHidden = true

            self.interactiveCell.transform = CGAffineTransform.identity

            return true
        }


        override func updateInteractiveMovementTargetPosition(_ targetPosition: CGPoint) {

            if (self.shouldSwap(newPoint: targetPosition)) {

                if let hoverIndexPath = self.indexPathForItem(at: targetPosition), let interactiveIndexPath = self.interactiveIndexPath {

                    let swapDescription = SwapDescription(firstItem: interactiveIndexPath.item, secondItem: hoverIndexPath.item)

                    if (!self.swapSet.contains(swapDescription)) {

                        self.swapSet.insert(swapDescription)

                        self.performBatchUpdates({
                            self.moveItem(at: interactiveIndexPath as IndexPath, to: hoverIndexPath)
                            self.moveItem(at: hoverIndexPath, to: interactiveIndexPath as IndexPath)
                        }, completion: {(finished) in
                            self.swapSet.remove(swapDescription)

                            self.dataSource?.collectionView!(self, moveItemAt: interactiveIndexPath as IndexPath, to: hoverIndexPath as IndexPath)

                            self.interactiveIndexPath = hoverIndexPath as NSIndexPath?
                        })
                    }
                }
            }

            self.interactiveView?.center = targetPosition
            self.previousPoint = targetPosition
        }

        override func endInteractiveMovement() {
            // Save the last rotation
            self.cleanup()
        }

        override func cancelInteractiveMovement() {
            self.cleanup()
        }

        func cleanup() {

            self.interactiveCell.isHidden = false
            self.interactiveView?.removeFromSuperview()
            self.interactiveView = nil
            self.interactiveCell.transform = CGAffineTransform.identity
            self.interactiveIndexPath = nil
            self.previousPoint = nil
            self.swapSet.removeAll()
        }

        func shouldSwap(newPoint: CGPoint) -> Bool {
            if let previousPoint = self.previousPoint {
                let distance = previousPoint.distanceToPoint(p: newPoint)
                return distance < SwappingCollectionView.distanceDelta
            }

            return false
        }

    }

我的collectionViewCell子类

import UIKit
import Firebase
import FirebaseDatabase

class CustomCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var imageView: UIImageView!


}

2 个答案:

答案 0 :(得分:1)

我建议不要操纵细胞的变换。我将设置UICollectionViewCell的自定义子类,并将所有内容放在内容视图中并旋转。

我还会为每个自定义单元格赋予currentRotation属性,并使其与变换的旋转同步。当您获取单元格或使单元格出列时,请检查它的currentRotation属性并使用它来查看是否需要旋转它。

答案 1 :(得分:0)

您应该将旋转状态存储在某处并将其应用于cellForItem(at:)。为了获得进一步的帮助,我需要来自视图控制器的更多代码。