使用UIPinchGestureRecognizer延迟缩放动画UICollectionView

时间:2018-03-01 18:10:00

标签: ios uicollectionview zooming uipinchgesturerecognizer

请告诉我“放大/缩小”UICollectionView并更改UICollectionViewCell大小的最佳方法。我现在正在使用UIPinchGestureRecognizer:当UICollectionView“放大”和“缩小”时,会出现严重的延迟和冻结。

当我执行PinchGestureRecognizer时,如何摆脱带状装饰?

以下是UICollectionViewController中UIPinchGestureRecognizer的实现代码:

class BlocksCollectionViewController: UICollectionViewController, UIGestureRecognizerDelegate {

  private var senderStartSize = CGFloat()
  private var senderNormalPosition = CGSize()

  override func viewDidLoad() {
    super.viewDidLoad()

    let pinchRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(_:)))
    pinchRecognizer.delegate = self
    collectionView?.addGestureRecognizer(pinchRecognizer)
  }

  @objc func handlePinch(_ sender: UIPinchGestureRecognizer) {
    guard let collection = collectionView else { return }
    guard let layout = collection.collectionViewLayout as? CustomCollectionViewLayout else { return }

    switch sender.state {
    case .began:

      senderStartSize = layout.cellSize

    case .changed:

      layout.cellSize = senderStartSize * sender.scale
      layout.invalidateLayout()

    default:
      break
    }
  }

  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
  }
}

下面的代码是сustomCollectionViewLayout:

class CustomCollectionViewLayout: UICollectionViewLayout {

  private var cellAttributes: [IndexPath: UICollectionViewLayoutAttributes] = [:]
  var cellSize: CGFloat = 7
  private var contentSize = CGSize.zero

  override var collectionViewContentSize: CGSize {
    return self.contentSize
  }

  override func prepare() {
    guard let collection = collectionView else { return }

    for section in 0...collection.numberOfSections - 2 {
      for item in 0...collection.numberOfItems(inSection: section) - 2 {
        let cellIndex = IndexPath(item: item, section: section)
        let xPos = CGFloat(item) * cellSize
        let yPos = CGFloat(section) * cellSize

        let attributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex)
        attributes.frame = CGRect(x: xPos, y: yPos, width: cellSize, height: cellSize)

        cellAttributes[cellIndex] = attributes
      }
    }

    let contentWidth = CGFloat(collection.numberOfItems(inSection: 0)) * cellSize
    let contentHeight = CGFloat(collection.numberOfSections) * cellSize
    contentSize = CGSize(width: contentWidth, height: contentHeight)

    let centerOffsetX = (collection.contentSize.width - collection.frame.size.width) / 2
    let centerOffsetY = (collection.contentSize.height - collection.frame.size.height) / 2
    let centerPoint = CGPoint(x: centerOffsetX, y: centerOffsetY)

    collection.setContentOffset(centerPoint, animated: false)
  }

  override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    var attributesInRect = [UICollectionViewLayoutAttributes]()

    for cellAttributes in cellAttributes.values {
      if rect.intersects(cellAttributes.frame) {
        attributesInRect.append(cellAttributes)
      }
    }
    return attributesInRect
  }

  override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    return cellAttributes[indexPath]
  }
}

result of this code (GIF)

3 个答案:

答案 0 :(得分:0)

很抱歉这样说,但我的猜测是问题不在你的代码中,而在于它的工作方式。因为我看到你有大量的细胞使它难以处理,这就是它开始滞后的原因。

您是否尝试过使用真实设备?比较最新的iPhone和旧的iPhone?我确定你会看到渲染速度的差异。

但无论如何,随着更多的计算/表达,你会有更多的表现。而且,循环很昂贵。

顺便说一句,作为一种解决方案(如果应用程序的业务方面接受它),您可以不放大/缩小,而是放大/缩小2个按钮。我认为它不会导致滞后,但它确实不那么酷。

答案 1 :(得分:0)

在这种情况下,我建议您使用Xcode Time Profiler来调试性能。您将找到导致延迟的部分并在以后进行优化。祝你好运:)

答案 2 :(得分:0)

由于我的收藏中有很多UICollectionViewCells,最好的方法是:

1)将UICollectionView放在containerView(简单的UIView)上,并将此容器放在UIScrollView上。

我限制缩放:

scrollView.minimumZoomScale = 1
scrollView.maximumZoomScale = 6

2)并使用了UIScrollViewDelegate的函数:

  func scrollViewDidZoom(_ scrollView: UIScrollView) {
   // Code for processing zoom - scrollView.zoomScale,
   // contentOffset, contentSize etc....
  }

  func viewForZooming(in scrollView: UIScrollView) -> UIView? {
    return containerView
  }

Result of this solution