Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/121.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UICollectionView单元格滚动到中间_Ios_Objective C_Uicollectionviewcell_Uicollectionviewlayout - Fatal编程技术网

Ios UICollectionView单元格滚动到中间

Ios UICollectionView单元格滚动到中间,ios,objective-c,uicollectionviewcell,uicollectionviewlayout,Ios,Objective C,Uicollectionviewcell,Uicollectionviewlayout,我正在UIViewController中使用UICollectionView 我的collectionview属性设置如下 现在我想细胞是在屏幕上的中心后滚动! 备选案文1: 备选案文2: 要实现选项2,我必须做些什么 更新: 最后我用了下面的代码作为滚动其他答案是不顺利的 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity

我正在UIViewController中使用UICollectionView

我的collectionview属性设置如下

现在我想细胞是在屏幕上的中心后滚动! 备选案文1:

备选案文2:

要实现选项2,我必须做些什么

更新:

最后我用了下面的代码作为滚动其他答案是不顺利的

  - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{    CGFloat offsetAdjustment = MAXFLOAT;
    CGFloat horizontalCenter = proposedContentOffset.x + (CGRectGetWidth(self.collectionView.bounds) / 2.0);

    CGRect targetRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);
    NSArray* array = [super layoutAttributesForElementsInRect:targetRect];

    for (UICollectionViewLayoutAttributes* layoutAttributes in array) {
        CGFloat itemHorizontalCenter = layoutAttributes.center.x;

        if (ABS(itemHorizontalCenter - horizontalCenter) < ABS(offsetAdjustment)) {
            offsetAdjustment = itemHorizontalCenter - horizontalCenter;
        }
    }    
    return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}
-(CGPoint)targetContentOffset for proposedContentOffset:(CGPoint)proposedContentOffset与CrollingVelocity:(CGPoint)速度
{CGFloat offsetAdjustment=MAXFLOAT;
CGFloat horizontalCenter=proposedContentOffset.x+(CGRectGetWidth(self.collectionView.bounds)/2.0);
CGRect targetRect=CGRectMake(proposedContentOffset.x,0.0,self.collectionView.bounds.size.width,self.collectionView.bounds.size.height);
NSArray*数组=[super-layouttributesforementsinrect:targetRect];
用于(UICollectionViewLayoutAttribute*数组中的LayoutAttribute){
CGFloat itemHorizontalCenter=布局属性.center.x;
if(ABS(项目水平中心-水平中心)
您可以在
UICollectionViewLayout
子类中重写
targetContentOffsetForProposedContentOffset:with CrollingVelocity:
方法,并在其中按如下方式计算偏移量:

@property (nonatomic, assign) CGFloat previousOffset;
@property (nonatomic, assign) NSInteger currentPage;

...

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
    NSInteger itemsCount = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:0];

    // Imitating paging behaviour
    // Check previous offset and scroll direction
    if ((self.previousOffset > self.collectionView.contentOffset.x) && (velocity.x < 0.0f)) {
        self.currentPage = MAX(self.currentPage - 1, 0);
    } else if ((self.previousOffset < self.collectionView.contentOffset.x) && (velocity.x > 0.0f)) {
        self.currentPage = MIN(self.currentPage + 1, itemsCount - 1);
    }

    // Update offset by using item size + spacing
    CGFloat updatedOffset = (self.itemSize.width + self.minimumInteritemSpacing) * self.currentPage;
    self.previousOffset = updatedOffset;

    return CGPointMake(updatedOffset, proposedContentOffset.y);
}
更新:附加Swift 4.2版本

...
collectionView.isPagingEnabled = false
...

class YourCollectionLayoutSubclass: UICollectionViewFlowLayout {

    private var previousOffset: CGFloat = 0
    private var currentPage: Int = 0

    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        guard let collectionView = collectionView else {
            return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity)
        }

        let itemsCount = collectionView.numberOfItems(inSection: 0)

        // Imitating paging behaviour
        // Check previous offset and scroll direction
        if previousOffset > collectionView.contentOffset.x && velocity.x < 0 {
            currentPage = max(currentPage - 1, 0)
        } else if previousOffset < collectionView.contentOffset.x && velocity.x > 0 {
            currentPage = min(currentPage + 1, itemsCount - 1)
        }

        // Update offset by using item size + spacing
        let updatedOffset = (itemSize.width + minimumInteritemSpacing) * CGFloat(currentPage)
        previousOffset = updatedOffset

        return CGPoint(x: updatedOffset, y: proposedContentOffset.y)
    }
}
。。。
collectionView.isPaginEnabled=false
...
类YourCollectionLayoutSubclass:UICollectionViewFlowLayout{
private var previousOffset:CGFloat=0
私有变量当前页:Int=0
覆盖func targetContentOffset(forProposedContentOffset proposedContentOffset:CGPoint,使用CrollingVelocity:CGPoint)->CGPoint{
guard let collectionView=collectionView else{
返回super.targetContentOffset(forProposedContentOffset:proposedContentOffset,带CrollingVelocity:velocity)
}
让itemsCount=collectionView.numberOfItems(第0节)
//模仿分页行为
//检查上一个偏移和滚动方向
如果previousOffset>collectionView.contentOffset.x&&velocity.x<0{
currentPage=最大值(currentPage-1,0)
}否则,如果previousOffset0{
currentPage=min(currentPage+1,ItemScont-1)
}
//使用项目大小+间距更新偏移量
让UpdateOffset=(itemSize.width+MinimumItemSpacing)*CGFloat(currentPage)
previousOffset=UpdateOffset
返回CGPoint(x:updateOffset,y:proposedContentOffset.y)
}
}
您可以使用代码
self.collectionView.scrollToItem(at:indepath,at:.centered水平,动画:true)
我不知道为什么每个人的答案都这么复杂,我只需在Interface Builder中启用
分页功能,它就能完美工作

这是@dmitry zhukov的Swift 3版本(谢谢你的提醒!)

class PagedCollectionLayout:UICollectionViewFlowLayout{
var previousOffset:CGFloat=0
var currentPage:CGFloat=0
覆盖func targetContentOffset(forProposedContentOffset proposedContentOffset:CGPoint,使用CrollingVelocity:CGPoint)->CGPoint{
设sup=super.targetContentOffset(forProposedContentOffset:proposedContentOffset,带CrollingVelocity:velocity)
警卫
让validCollection=collectionView,
让dataSource=validCollection.dataSource
else{return sup}
让itemsCount=dataSource.collectionView(validCollection,numberOfItemsInSection:0)
//模仿分页行为
//检查上一个偏移和滚动方向
如果(previousOffset>validCollection.contentOffset.x)&(velocity.x<0){
currentPage=最大值(currentPage-1,0)
}
否则如果(previousOffset0){
currentPage=min(currentPage+1,CGFloat(itemscont-1))
}
//使用项目大小+间距更新偏移量
让UpdateOffset=((itemSize.width+MinimumItemSpacing)*currentPage)
self.previousOffset=updateoffset
设updatedPoint=CGPoint(x:UpdateOffset,y:proposedContentOffset.y)
返回更新点
}
}

我找到了很多信息和解决方案

现在,我用这个

在UICollectionViewFlowLayout替代上:

override public func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {

    if display != .inline {
        return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity)
    }

    guard let collectionView = collectionView else {
        return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity)
    }

    let willtoNextX: CGFloat

    if proposedContentOffset.x <= 0 || collectionView.contentOffset == proposedContentOffset {
        willtoNextX = proposedContentOffset.x
    } else {

        let width = collectionView.bounds.size.width
        willtoNextX = collectionView.contentOffset.x + (velocity.x > 0 ?  width : -width)
    }

    let targetRect = CGRect(x: willtoNextX, y: 0, width: collectionView.bounds.size.width, height: collectionView.bounds.size.height)

    var offsetAdjustCoefficient = CGFloat.greatestFiniteMagnitude

    let horizontalOffset = proposedContentOffset.x + collectionView.contentInset.left

    let layoutAttributesArray = super.layoutAttributesForElements(in: targetRect)

    layoutAttributesArray?.forEach({ (layoutAttributes) in
        let itemOffset = layoutAttributes.frame.origin.x
        if fabsf(Float(itemOffset - horizontalOffset)) < fabsf(Float(offsetAdjustCoefficient)) {
            offsetAdjustCoefficient = itemOffset - horizontalOffset
        }
    })

    return CGPoint(x: proposedContentOffset.x + offsetAdjustCoefficient, y: proposedContentOffset.y)
}
现在,细胞在中心


在设置正确的
itemSize
left
right
插入后,我更喜欢这样做,而不是将布局子类化

//Setting decelerationRate to fast gives a nice experience
collectionView.decelerationRate = .fast

//Add this to your view anywhere
func centerCell () {
    let centerPoint = CGPoint(x: collectionView.contentOffset.x + collectionView.frame.midX, y: 100)
    if let path = collectionView.indexPathForItem(at: centerPoint) {
        collectionView.scrollToItem(at: path, at: .centeredHorizontally, animated: true)
    }
}

//Set collectionView.delegate = self then add below funcs
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
   centerCell()
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
    centerCell()
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if !decelerate {
        centerCell()
    }
}

我的解决方案是像分页一样滚动

//
collectionview.isPaging = false
//

class CollectionLayoutSubclass: UICollectionViewFlowLayout {

    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        var point = super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity)
        guard let collectionView = collectionView else {
            return point
        }
        let cells = collectionView.visibleCells
        let centerPoint = collectionView.center
        var cellFrame: CGRect = CGRect.zero
        for cell in cells {
            cellFrame = collectionView.convert(cell.frame, to: collectionView.superview)
            var newCenterPoint: CGPoint = centerPoint
            if velocity.x > 0 {
                newCenterPoint = CGPoint(x: centerPoint.x * 1.5, y: centerPoint.y)
            } else if velocity.x < 0 {
                newCenterPoint = CGPoint(x: centerPoint.x * 0.5, y: centerPoint.y)
            }
            guard cellFrame.contains(newCenterPoint) else {
                continue
            }
            let x = collectionView.frame.width / 2 - cell.frame.width / 2
            point.x = cell.frame.origin.x - x
            break
        }
        return point
    }
}
//
collectionview.isPaging=false
//
类CollectionLayoutSubclass:UICollectionViewFlowLayout{
覆盖func targetContentOffset(forProposedContentOffset proposedContentOffset:CGPoint,使用CrollingVelocity:CGPoint)->CGPoint{
var point=super.targetContentOffset(forProposedContentOffset:proposedContentOffset,带CrollingVelocity:velocity)
guard let collectionView=collectionView else{
返回点
}
let cells=collectionView.visibleCells
让centerPoint=collectionView.center
var cellFrame:CGRect=CGRect.zero
细胞中的细胞{
cellFrame=collectionView.convert(cell.frame,to:collectionView.superview)
var newCenterPoint:CGPoint=centerPoint
如果速度.x>0{
newCenterPoint=CGPoint(x:centerPoint.x*1.5,y:centerPoint.y)
}否则,如果速度.x<0{
newCenterPoint=CGPoint(x:centerPoint.x*0.5,y:centerPoint.y)
}
collectionView.decelerationRate = .fast
collectionView.isPagingEnabled = false
collectionView.contentInset = UIEdgeInsets.init(top: 0, left: 16, bottom: 0, right: 16)
//Setting decelerationRate to fast gives a nice experience
collectionView.decelerationRate = .fast

//Add this to your view anywhere
func centerCell () {
    let centerPoint = CGPoint(x: collectionView.contentOffset.x + collectionView.frame.midX, y: 100)
    if let path = collectionView.indexPathForItem(at: centerPoint) {
        collectionView.scrollToItem(at: path, at: .centeredHorizontally, animated: true)
    }
}

//Set collectionView.delegate = self then add below funcs
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
   centerCell()
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
    centerCell()
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if !decelerate {
        centerCell()
    }
}
//
collectionview.isPaging = false
//

class CollectionLayoutSubclass: UICollectionViewFlowLayout {

    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        var point = super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity)
        guard let collectionView = collectionView else {
            return point
        }
        let cells = collectionView.visibleCells
        let centerPoint = collectionView.center
        var cellFrame: CGRect = CGRect.zero
        for cell in cells {
            cellFrame = collectionView.convert(cell.frame, to: collectionView.superview)
            var newCenterPoint: CGPoint = centerPoint
            if velocity.x > 0 {
                newCenterPoint = CGPoint(x: centerPoint.x * 1.5, y: centerPoint.y)
            } else if velocity.x < 0 {
                newCenterPoint = CGPoint(x: centerPoint.x * 0.5, y: centerPoint.y)
            }
            guard cellFrame.contains(newCenterPoint) else {
                continue
            }
            let x = collectionView.frame.width / 2 - cell.frame.width / 2
            point.x = cell.frame.origin.x - x
            break
        }
        return point
    }
}