ios - 未调用 targetContentOffsetForProposedContentOffset

标签 ios swift ipad uicollectionview uicollectionviewlayout

好吧,我有这个 UICollectionView:

       let flowLayout = CalendarFlowLayout()
        flowLayout.scrollDirection = UICollectionViewScrollDirection.Horizontal
        flowLayout.minimumInteritemSpacing = 0
        flowLayout.minimumLineSpacing = 32
        flowLayout.itemSize = CGSize(width: 544, height: 573)
        let horizontalInsets = (self.frame.size.width - flowLayout.itemSize.width)/2
        flowLayout.sectionInset = UIEdgeInsets(top: 0, left: horizontalInsets, bottom: 0, right: -horizontalInsets)

        self.collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: CGRectGetWidth(self.bounds), height: flowLayout.itemSize.height), collectionViewLayout: flowLayout)


        self.collectionView.scrollsToTop = false
        self.collectionView.registerClass(GIMonthCollectionViewCell.self, forCellWithReuseIdentifier: "MonthCell")
        self.addSubview(self.collectionView)
        self.collectionView.showsHorizontalScrollIndicator = false
        self.collectionView.showsVerticalScrollIndicator = false
        self.collectionView.backgroundColor = UIColor.whiteColor()
        self.collectionView.backgroundView?.backgroundColor = UIColor.whiteColor()
        self.collectionView.dataSource = self
        self.collectionView.delegate = self


        self.collectionView.snp_makeConstraints { (make) -> Void in
            make.top.equalTo(self)
            make.bottom.equalTo(self)
            make.left.equalTo(self)
            make.right.equalTo(self)
        }
        self.layoutSubviews()
        self.collectionView.scrollToItemAtIndexPath(NSIndexPath(forItem: 13, inSection: 0), atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: false)

和 CalendarFlowLayout

class CalendarFlowLayout: UICollectionViewFlowLayout {
    var pathForFocusItem: NSIndexPath?

    //This piece of code will make the cell always stay on center, like a paging, but with the Cell width as parameter, not the collectionView width
    override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        var offsetAdjustment = CGFloat(FLT_MAX)

        if let unwrapedCollectionView = self.collectionView {
            let collectionViewWidth = CGRectGetWidth(unwrapedCollectionView.bounds)
            let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionViewWidth, height: CGRectGetHeight(unwrapedCollectionView.bounds))

            let layoutAttributesForElementsInTargetRect = super.layoutAttributesForElementsInRect(targetRect) as! Array<UICollectionViewLayoutAttributes>

            for currentLayoutAttributes in layoutAttributesForElementsInTargetRect {

                let itemOffset = CGRectGetMinX(currentLayoutAttributes.frame)
                let horizontalOffset = proposedContentOffset.x + (collectionViewWidth - CGRectGetWidth(currentLayoutAttributes.frame))/2

                if abs(itemOffset - horizontalOffset) < abs(offsetAdjustment) {
                    offsetAdjustment = itemOffset - horizontalOffset
                }
            }

            return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
        }

        return super.targetContentOffsetForProposedContentOffset(proposedContentOffset, withScrollingVelocity: velocity)
    }


    override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint) -> CGPoint {
        if let unwrapedPathForForcusItem = self.pathForFocusItem {
            let layoutAttributesForFocusedItem = self.layoutAttributesForItemAtIndexPath(unwrapedPathForForcusItem)
            return CGPoint(x: layoutAttributesForFocusedItem.frame.origin.x - self.collectionView!.contentInset.left,  y: layoutAttributesForFocusedItem.frame.origin.y - self.collectionView!.contentInset.top)
        }

        return super.targetContentOffsetForProposedContentOffset(proposedContentOffset)
    }
}

嗯,出于某种原因,“targetContentOffsetForProposedContentOffset”永远不会被调用。

为什么我要它被调用?当 View 旋转时,我想根据 View 的新比例重新定位单元格,而不需要在 collectionView 上调用 reloadData()。

知道为什么会这样吗?

最佳答案

我能够使用您的代码并调用 targetContentOffsetForProposedContentOffset:withScrollingVelocity。我不能 100% 确定您的代码有什么问题,但我看到的最明显的问题是:

你正在调用 self.frameself.layoutSubviews 的事实告诉我你正在 中创建一个 UICollectionView >UIView。这在实用上是错误的。您的 UICollectionView 应该在 UIViewController 中创建,或者更好的是,使用 UICollectionViewController 为您创建一个 UICollectionView。在下面的代码中,我创建了一个空白示例项目并将您的代码附加到根 UIViewController

希望对您有所帮助!

import UIKit

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
    private var collectionView: UICollectionView?

    override func viewDidLoad() {
        super.viewDidLoad()

        let flowLayout = CalendarFlowLayout()
        flowLayout.scrollDirection = UICollectionViewScrollDirection.Horizontal
        flowLayout.minimumInteritemSpacing = 0
        flowLayout.minimumLineSpacing = 32
        flowLayout.itemSize = CGSize(width: 544, height: 573)
        let horizontalInsets = (self.view.frame.size.width - flowLayout.itemSize.width)/2
        flowLayout.sectionInset = UIEdgeInsets(top: 0, left: horizontalInsets, bottom: 0, right: -horizontalInsets)

        let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: CGRectGetWidth(self.view.bounds), height: flowLayout.itemSize.height), collectionViewLayout: flowLayout)
        self.collectionView = collectionView
        collectionView.scrollsToTop = false
        collectionView.registerClass(GIMonthCollectionViewCell.self, forCellWithReuseIdentifier: "MonthCell")
        self.view.addSubview(collectionView)
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.showsVerticalScrollIndicator = false
        collectionView.backgroundColor = UIColor.whiteColor()
        collectionView.backgroundView?.backgroundColor = UIColor.whiteColor()
        collectionView.dataSource = self
        collectionView.delegate = self

        collectionView.scrollToItemAtIndexPath(NSIndexPath(forItem: 13, inSection: 0), atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: false)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 50
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MonthCell", forIndexPath: indexPath)
        return cell
    }
}

class GIMonthCollectionViewCell: UICollectionViewCell {
    override init(frame: CGRect) {
        super.init(frame: frame)

        self.backgroundColor = UIColor.magentaColor()
        self.layer.borderColor = UIColor.whiteColor().colorWithAlphaComponent(0.5).CGColor
        self.layer.borderWidth = 4
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class CalendarFlowLayout: UICollectionViewFlowLayout {
    var pathForFocusItem: NSIndexPath?

    //This piece of code will make the cell always stay on center, like a paging, but with the Cell width as parameter, not the collectionView width
    override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        var offsetAdjustment = CGFloat(FLT_MAX)

        if let unwrapedCollectionView = self.collectionView {
            let collectionViewWidth = CGRectGetWidth(unwrapedCollectionView.bounds)
            let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionViewWidth, height: CGRectGetHeight(unwrapedCollectionView.bounds))

            if let layoutAttributesForElementsInTargetRect = super.layoutAttributesForElementsInRect(targetRect) {
                for currentLayoutAttributes in layoutAttributesForElementsInTargetRect {

                    let itemOffset = CGRectGetMinX(currentLayoutAttributes.frame)
                    let horizontalOffset = proposedContentOffset.x + (collectionViewWidth - CGRectGetWidth(currentLayoutAttributes.frame))/2

                    if abs(itemOffset - horizontalOffset) < abs(offsetAdjustment) {
                        offsetAdjustment = itemOffset - horizontalOffset
                    }
                }
            }

            return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
        }

        return super.targetContentOffsetForProposedContentOffset(proposedContentOffset, withScrollingVelocity: velocity)
    }


    override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint) -> CGPoint {
        if let unwrapedPathForForcusItem = self.pathForFocusItem {
            let layoutAttributesForFocusedItem = self.layoutAttributesForItemAtIndexPath(unwrapedPathForForcusItem)
            return CGPoint(x: layoutAttributesForFocusedItem!.frame.origin.x - self.collectionView!.contentInset.left,  y: layoutAttributesForFocusedItem!.frame.origin.y - self.collectionView!.contentInset.top)
        }

        return super.targetContentOffsetForProposedContentOffset(proposedContentOffset)
    }
}

关于ios - 未调用 targetContentOffsetForProposedContentOffset,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32509455/

相关文章:

ios - 如何使用 Skobbler 缩放到 map 上的当前位置

.net - iOS 应用程序的 WCF 或 Web 服务 (.asmx)?

iphone - 将JSON写入文件。但是你怎么读回来呢?

ios - 动态隐藏状态栏时如何保留状态栏占用的空间?

swift - 自动续订订阅免费试用无效

iPad 模态视图 Controller 的自定义尺寸

ios - 避免多行 UILabel 中的单个字符换行

iphone - 请求设备 token

iphone - 在类之间传递数据/异步请求/iOS

ios - 没有 GPS iOS 的室内路由