targetContentOffsetForProposedContentOffset:withScrollingVelocity without subclassing UICollectionViewFlowLayout

I’ve got a very simple collectionView in my app (just a single row of square thumbnail images).

I’d like to intercept the scrolling so that the offset always leaves a full image at the left side. At the moment it scrolls to wherever and will leave cut off images.

  • Add 90 min to NSDate
  • iPhone, call another phone number in response to the first not answering?
  • Trying to debug mystery sinewave using AKMIDISampler in Audiokit
  • How to get formatted address NSString from AddressDictionary?
  • Core data not saving my data
  • Objective C: Where to remove observer for NSNotification?
  • Anyway, I know I need to use the function

    - (CGPoint)targetContentOffsetForProposedContentOffset:withScrollingVelocity
    

    to do this but I’m just using a standard UICollectionViewFlowLayout. I’m not subclassing it.

    Is there any way of intercepting this without subclassing UICollectionViewFlowLayout?

    Thanks

    14 Solutions Collect From Internet About “targetContentOffsetForProposedContentOffset:withScrollingVelocity without subclassing UICollectionViewFlowLayout”

    OK, answer is no, there is no way to do this without subclassing UICollectionViewFlowLayout.

    However, subclassing it is incredibly easy for anyone who is reading this in the future.

    First I set up the subclass call MyCollectionViewFlowLayout and then in interface builder I changed the collection view layout to Custom and selected my flow layout subclass.

    Because you’re doing it this way you can’t specify items sizes, etc… in IB so in MyCollectionViewFlowLayout.m I have this…

    - (void)awakeFromNib
    {
        self.itemSize = CGSizeMake(75.0, 75.0);
        self.minimumInteritemSpacing = 10.0;
        self.minimumLineSpacing = 10.0;
        self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        self.sectionInset = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0);
    }
    

    This sets up all the sizes for me and the scroll direction.

    Then …

    - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
    {
        CGFloat offsetAdjustment = MAXFLOAT;
        CGFloat horizontalOffset = proposedContentOffset.x + 5;
    
        CGRect targetRect = CGRectMake(proposedContentOffset.x, 0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);
    
        NSArray *array = [super layoutAttributesForElementsInRect:targetRect];
    
        for (UICollectionViewLayoutAttributes *layoutAttributes in array) {
            CGFloat itemOffset = layoutAttributes.frame.origin.x;
            if (ABS(itemOffset - horizontalOffset) < ABS(offsetAdjustment)) {
                offsetAdjustment = itemOffset - horizontalOffset;
            }
        }
    
        return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
    }
    

    This ensures that the scrolling ends with a margin of 5.0 on the left hand edge.

    That’s all I needed to do. I didn’t need to set the flow layout in code at all.

    Dan’s solution is flawed. It does not handle user flicking well. The cases when user flicks fast and scroll did not move so much, have animation glitches.

    My proposed alternative implementation has the same pagination as proposed before, but handles user flicking between pages.

     #pragma mark - Pagination
     - (CGFloat)pageWidth {
         return self.itemSize.width + self.minimumLineSpacing;
     }
    
     - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
     {           
            CGFloat rawPageValue = self.collectionView.contentOffset.x / self.pageWidth;
            CGFloat currentPage = (velocity.x > 0.0) ? floor(rawPageValue) : ceil(rawPageValue);
            CGFloat nextPage = (velocity.x > 0.0) ? ceil(rawPageValue) : floor(rawPageValue);
    
            BOOL pannedLessThanAPage = fabs(1 + currentPage - rawPageValue) > 0.5;
            BOOL flicked = fabs(velocity.x) > [self flickVelocity];
            if (pannedLessThanAPage && flicked) {
                proposedContentOffset.x = nextPage * self.pageWidth;
            } else {
                proposedContentOffset.x = round(rawPageValue) * self.pageWidth;
            }
    
            return proposedContentOffset;
     }
    
     - (CGFloat)flickVelocity {
         return 0.3;
     }
    

    After long testing I found solution to snap to center with custom cell width (each cell has diff. width) which fixes the flickering. Feel free to improve the script.

    - (CGPoint) targetContentOffsetForProposedContentOffset: (CGPoint) proposedContentOffset withScrollingVelocity: (CGPoint)velocity
    {
        CGFloat offSetAdjustment = MAXFLOAT;
        CGFloat horizontalCenter = (CGFloat) (proposedContentOffset.x + (self.collectionView.bounds.size.width / 2.0));
    
        //setting fastPaging property to NO allows to stop at page on screen (I have pages lees, than self.collectionView.bounds.size.width)
        CGRect targetRect = CGRectMake(self.fastPaging ? proposedContentOffset.x : self.collectionView.contentOffset.x, 
                                       0.0,
                                       self.collectionView.bounds.size.width,
                                       self.collectionView.bounds.size.height);
    
        NSArray *attributes = [self layoutAttributesForElementsInRect:targetRect];
        NSPredicate *cellAttributesPredicate = [NSPredicate predicateWithBlock: ^BOOL(UICollectionViewLayoutAttributes * _Nonnull evaluatedObject,
                                                                                 NSDictionary<NSString *,id> * _Nullable bindings) 
        {
            return (evaluatedObject.representedElementCategory == UICollectionElementCategoryCell); 
        }];        
    
        NSArray *cellAttributes = [attributes filteredArrayUsingPredicate: cellAttributesPredicate];
    
        UICollectionViewLayoutAttributes *currentAttributes;
    
        for (UICollectionViewLayoutAttributes *layoutAttributes in cellAttributes)
        {
            CGFloat itemHorizontalCenter = layoutAttributes.center.x;
            if (ABS(itemHorizontalCenter - horizontalCenter) < ABS(offSetAdjustment))
            {
                currentAttributes   = layoutAttributes;
                offSetAdjustment    = itemHorizontalCenter - horizontalCenter;
            }
        }
    
        CGFloat nextOffset          = proposedContentOffset.x + offSetAdjustment;
    
        proposedContentOffset.x     = nextOffset;
        CGFloat deltaX              = proposedContentOffset.x - self.collectionView.contentOffset.x;
        CGFloat velX                = velocity.x;
    
        // detection form  gist.github.com/rkeniger/7687301
        // based on http://stackoverflow.com/a/14291208/740949
        if (fabs(deltaX) <= FLT_EPSILON || fabs(velX) <= FLT_EPSILON || (velX > 0.0 && deltaX > 0.0) || (velX < 0.0 && deltaX < 0.0)) 
        {
    
        } 
        else if (velocity.x > 0.0) 
        {
           // revert the array to get the cells from the right side, fixes not correct center on different size in some usecases
            NSArray *revertedArray = [[array reverseObjectEnumerator] allObjects];
    
            BOOL found = YES;
            float proposedX = 0.0;
    
            for (UICollectionViewLayoutAttributes *layoutAttributes in revertedArray)
            {
                if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell)
                {
                    CGFloat itemHorizontalCenter = layoutAttributes.center.x;
                    if (itemHorizontalCenter > proposedContentOffset.x) {
                         found = YES;
                         proposedX = nextOffset + (currentAttributes.frame.size.width / 2) + (layoutAttributes.frame.size.width / 2);
                    } else {
                         break;
                    }
                }
            }
    
           // dont set on unfound element
            if (found) {
                proposedContentOffset.x = proposedX;
            }
        } 
        else if (velocity.x < 0.0) 
        {
            for (UICollectionViewLayoutAttributes *layoutAttributes in cellAttributes)
            {
                CGFloat itemHorizontalCenter = layoutAttributes.center.x;
                if (itemHorizontalCenter > proposedContentOffset.x) 
                {
                    proposedContentOffset.x = nextOffset - ((currentAttributes.frame.size.width / 2) + (layoutAttributes.frame.size.width / 2));
                    break;
                }
            }
        }
    
        proposedContentOffset.y = 0.0;
    
        return proposedContentOffset;
    }
    

    While this answer has been a great help to me, there is a noticeable flicker when you swipe fast on a small distance. It’s much easier to reproduce it on the device.

    I found that this always happens when collectionView.contentOffset.x - proposedContentOffset.x and velocity.x have different sings.

    My solution was to ensure that proposedContentOffset is more than contentOffset.x if velocity is positive, and less if it is negative. It’s in C# but should be fairly simple to translate to Objective C:

    public override PointF TargetContentOffset (PointF proposedContentOffset, PointF scrollingVelocity)
    {
        /* Determine closest edge */
    
        float offSetAdjustment = float.MaxValue;
        float horizontalCenter = (float) (proposedContentOffset.X + (this.CollectionView.Bounds.Size.Width / 2.0));
    
        RectangleF targetRect = new RectangleF (proposedContentOffset.X, 0.0f, this.CollectionView.Bounds.Size.Width, this.CollectionView.Bounds.Size.Height);
        var array = base.LayoutAttributesForElementsInRect (targetRect);
    
        foreach (var layoutAttributes in array) {
            float itemHorizontalCenter = layoutAttributes.Center.X;
            if (Math.Abs (itemHorizontalCenter - horizontalCenter) < Math.Abs (offSetAdjustment)) {
                offSetAdjustment = itemHorizontalCenter - horizontalCenter;
            }
        }
    
        float nextOffset = proposedContentOffset.X + offSetAdjustment;
    
        /*
         * ... unless we end up having positive speed
         * while moving left or negative speed while moving right.
         * This will cause flicker so we resort to finding next page
         * in the direction of velocity and use it.
         */
    
        do {
            proposedContentOffset.X = nextOffset;
    
            float deltaX = proposedContentOffset.X - CollectionView.ContentOffset.X;
            float velX = scrollingVelocity.X;
    
            // If their signs are same, or if either is zero, go ahead
            if (Math.Sign (deltaX) * Math.Sign (velX) != -1)
                break;
    
            // Otherwise, look for the closest page in the right direction
            nextOffset += Math.Sign (scrollingVelocity.X) * SnapStep;
        } while (IsValidOffset (nextOffset));
    
        return proposedContentOffset;
    }
    
    bool IsValidOffset (float offset)
    {
        return (offset >= MinContentOffset && offset <= MaxContentOffset);
    }
    

    This code is using MinContentOffset, MaxContentOffset and SnapStep which should be trivial for you to define. In my case they turned out to be

    float MinContentOffset {
        get { return -CollectionView.ContentInset.Left; }
    }
    
    float MaxContentOffset {
        get { return MinContentOffset + CollectionView.ContentSize.Width - ItemSize.Width; }
    }
    
    float SnapStep {
        get { return ItemSize.Width + MinimumLineSpacing; }
    }
    

    refer to this answer by Dan Abramov here’s Swift version

        override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        var _proposedContentOffset = CGPoint(x: proposedContentOffset.x, y: proposedContentOffset.y)
        var offSetAdjustment: CGFloat = CGFloat.max
        let horizontalCenter: CGFloat = CGFloat(proposedContentOffset.x + (self.collectionView!.bounds.size.width / 2.0))
    
        let targetRect = CGRect(x: proposedContentOffset.x, y: 0.0, width: self.collectionView!.bounds.size.width, height: self.collectionView!.bounds.size.height)
    
        let array: [UICollectionViewLayoutAttributes] = self.layoutAttributesForElementsInRect(targetRect)! as [UICollectionViewLayoutAttributes]
        for layoutAttributes: UICollectionViewLayoutAttributes in array {
            if (layoutAttributes.representedElementCategory == UICollectionElementCategory.Cell) {
                let itemHorizontalCenter: CGFloat = layoutAttributes.center.x
                if (abs(itemHorizontalCenter - horizontalCenter) < abs(offSetAdjustment)) {
                    offSetAdjustment = itemHorizontalCenter - horizontalCenter
                }
            }
        }
    
        var nextOffset: CGFloat = proposedContentOffset.x + offSetAdjustment
    
        repeat {
            _proposedContentOffset.x = nextOffset
            let deltaX = proposedContentOffset.x - self.collectionView!.contentOffset.x
            let velX = velocity.x
    
            if (deltaX == 0.0 || velX == 0 || (velX > 0.0 && deltaX > 0.0) || (velX < 0.0 && deltaX < 0.0)) {
                break
            }
    
            if (velocity.x > 0.0) {
                nextOffset = nextOffset + self.snapStep()
            } else if (velocity.x < 0.0) {
                nextOffset = nextOffset - self.snapStep()
            }
        } while self.isValidOffset(nextOffset)
    
        _proposedContentOffset.y = 0.0
    
        return _proposedContentOffset
    }
    
    func isValidOffset(offset: CGFloat) -> Bool {
        return (offset >= CGFloat(self.minContentOffset()) && offset <= CGFloat(self.maxContentOffset()))
    }
    
    func minContentOffset() -> CGFloat {
        return -CGFloat(self.collectionView!.contentInset.left)
    }
    
    func maxContentOffset() -> CGFloat {
        return CGFloat(self.minContentOffset() + self.collectionView!.contentSize.width - self.itemSize.width)
    }
    
    func snapStep() -> CGFloat {
        return self.itemSize.width + self.minimumLineSpacing;
    }
    

    or gist here https://gist.github.com/katopz/8b04c783387f0c345cd9

    I just want to put here the Swift version of the accepted answer.

    override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        var offsetAdjustment = CGFloat.greatestFiniteMagnitude
        let horizontalOffset = proposedContentOffset.x
        let targetRect = CGRect(origin: CGPoint(x: proposedContentOffset.x, y: 0), size: self.collectionView!.bounds.size)
    
        for layoutAttributes in super.layoutAttributesForElements(in: targetRect)! {
            let itemOffset = layoutAttributes.frame.origin.x
            if (abs(itemOffset - horizontalOffset) < abs(offsetAdjustment)) {
                offsetAdjustment = itemOffset - horizontalOffset
            }
        }
    
        return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
    }
    

    Valid for Swift 3.

    I prefer to allow user flicking through several pages. So here is my version of targetContentOffsetForProposedContentOffset (which based on DarthMike answer) for vertical layout.

    - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
        CGFloat approximatePage = self.collectionView.contentOffset.y / self.pageHeight;
        CGFloat currentPage = (velocity.y < 0.0) ? floor(approximatePage) : ceil(approximatePage);
    
        NSInteger flickedPages = ceil(velocity.y / self.flickVelocity);
    
        if (flickedPages) {
            proposedContentOffset.y = (currentPage + flickedPages) * self.pageHeight;
        } else {
            proposedContentOffset.y = currentPage * self.pageHeight;
        }
    
        return proposedContentOffset;
    }
    
    - (CGFloat)pageHeight {
        return self.itemSize.height + self.minimumLineSpacing;
    }
    
    - (CGFloat)flickVelocity {
        return 1.2;
    }
    

    Fogmeisters answer worked for me unless I scrolled to the end of the row. My cells don’t fit neatly on the screen so it would scroll to the end and jump back with a jerk so that the last cell always overlapped the right edge of the screen.

    To prevent this add the following line of code at the start of the targetcontentoffset method

    if(proposedContentOffset.x>self.collectionViewContentSize.width-320-self.sectionInset.right)
        return proposedContentOffset;
    

    a small issue I encountered while using targetContentOffsetForProposedContentOffset is a problem with the last cell not adjusting according to the new point I returned.
    I found out that the CGPoint I returned had a Y value bigger then allowed so i used the following code at the end of my targetContentOffsetForProposedContentOffset implementation:

    // if the calculated y is bigger then the maximum possible y we adjust accordingly
    CGFloat contentHeight = self.collectionViewContentSize.height;
    CGFloat collectionViewHeight = self.collectionView.bounds.size.height;
    CGFloat maxY = contentHeight - collectionViewHeight;
    if (newY > maxY)
    {
        newY = maxY;
    }
    
    return CGPointMake(0, newY);
    

    just to make it clearer this is my full layout implementation which just imitates vertical paging behavior:

    - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
    {
        return [self targetContentOffsetForProposedContentOffset:proposedContentOffset];
    }
    
    - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
    {
        CGFloat heightOfPage = self.itemSize.height;
        CGFloat heightOfSpacing = self.minimumLineSpacing;
    
        CGFloat numOfPage = lround(proposedContentOffset.y / (heightOfPage + heightOfSpacing));
        CGFloat newY = numOfPage * (heightOfPage + heightOfSpacing);
    
        // if the calculated y is bigger then the maximum possible y we adjust accordingly
        CGFloat contentHeight = self.collectionViewContentSize.height;
        CGFloat collectionViewHeight = self.collectionView.bounds.size.height;
        CGFloat maxY = contentHeight - collectionViewHeight;
        if (newY > maxY)
        {
            newY = maxY;
        }
    
        return CGPointMake(0, newY);
    }
    

    hopefully this will save someone some time and a headache

    Here is my Swift solution on a horizontally scrolling collection view. It’s simple, sweet and avoids any flickering.

      override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        guard let collectionView = collectionView else { return proposedContentOffset }
    
        let currentXOffset = collectionView.contentOffset.x
        let nextXOffset = proposedContentOffset.x
        let maxIndex = ceil(currentXOffset / pageWidth())
        let minIndex = floor(currentXOffset / pageWidth())
    
        var index: CGFloat = 0
    
        if nextXOffset > currentXOffset {
          index = maxIndex
        } else {
          index = minIndex
        }
    
        let xOffset = pageWidth() * index
        let point = CGPointMake(xOffset, 0)
    
        return point
      }
    
      func pageWidth() -> CGFloat {
        return itemSize.width + minimumInteritemSpacing
      }
    

    @AndrĂ© Abreu‘s Code

    Swift3 version

    class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {
        override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
            var offsetAdjustment = CGFloat.greatestFiniteMagnitude
            let horizontalOffset = proposedContentOffset.x
            let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: self.collectionView!.bounds.size.width, height: self.collectionView!.bounds.size.height)
            for layoutAttributes in super.layoutAttributesForElements(in: targetRect)! {
                let itemOffset = layoutAttributes.frame.origin.x
                if abs(itemOffset - horizontalOffset) < abs(offsetAdjustment){
                    offsetAdjustment = itemOffset - horizontalOffset
                }
            }
            return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
        }
    }
    

    Swift 4

    The easiest solution for collection view with cells of one size (horizontal scroll):

    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        guard let collectionView = collectionView else { return proposedContentOffset }
    
        // Calculate width of your page
        let pageWidth = calculatedPageWidth()
    
        // Calculate proposed page
        let proposedPage = round(proposedContentOffset.x / pageWidth)
    
        // Adjust necessary offset
        let xOffset = pageWidth * proposedPage - collectionView.contentInset.left
    
        return CGPoint(x: xOffset, y: 0)
    }
    
    func calculatedPageWidth() -> CGFloat {
        return itemSize.width + minimumInteritemSpacing
    }
    

    A shorter solution (assuming you’re caching your layout attributes):

    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        let proposedEndFrame = CGRect(x: proposedContentOffset.x, y: 0, width: collectionView!.bounds.width, height: collectionView!.bounds.height)
        let targetLayoutAttributes = cache.max { $0.frame.intersection(proposedEndFrame).width < $1.frame.intersection(proposedEndFrame).width }!
        return CGPoint(x: targetLayoutAttributes.frame.minX - horizontalPadding, y: 0)
    }
    

    To put this in context:

    class Layout : UICollectionViewLayout {
        private var cache: [UICollectionViewLayoutAttributes] = []
        private static let horizontalPadding: CGFloat = 16
        private static let interItemSpacing: CGFloat = 8
    
        override func prepare() {
            let (itemWidth, itemHeight) = (collectionView!.bounds.width - 2 * Layout.horizontalPadding, collectionView!.bounds.height)
            cache.removeAll()
            let count = collectionView!.numberOfItems(inSection: 0)
            var x: CGFloat = Layout.horizontalPadding
            for item in (0..<count) {
                let indexPath = IndexPath(item: item, section: 0)
                let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
                attributes.frame = CGRect(x: x, y: 0, width: itemWidth, height: itemHeight)
                cache.append(attributes)
                x += itemWidth + Layout.interItemSpacing
            }
        }
    
        override var collectionViewContentSize: CGSize {
            let width: CGFloat
            if let maxX = cache.last?.frame.maxX {
                width = maxX + Layout.horizontalPadding
            } else {
                width = collectionView!.width
            }
            return CGSize(width: width, height: collectionView!.height)
        }
    
        override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
            return cache.first { $0.indexPath == indexPath }
        }
    
        override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
            return cache.filter { $0.frame.intersects(rect) }
        }
    
        override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
            let proposedEndFrame = CGRect(x: proposedContentOffset.x, y: 0, width: collectionView!.bounds.width, height: collectionView!.bounds.height)
            let targetLayoutAttributes = cache.max { $0.frame.intersection(proposedEndFrame).width < $1.frame.intersection(proposedEndFrame).width }!
            return CGPoint(x: targetLayoutAttributes.frame.minX - Layout.horizontalPadding, y: 0)
        }
    }
    

    For those looking for a solution in Swift:

    class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {
        private let collectionViewHeight: CGFloat = 200.0
        private let screenWidth: CGFloat = UIScreen.mainScreen().bounds.width
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            self.itemSize = CGSize(width: [InsertItemWidthHere], height: [InsertItemHeightHere])
            self.minimumInteritemSpacing = [InsertItemSpacingHere]
            self.scrollDirection = .Horizontal
            let inset = (self.screenWidth - CGFloat(self.itemSize.width)) / 2
            self.collectionView?.contentInset = UIEdgeInsets(top: 0,
                                                             left: inset,
                                                             bottom: 0,
                                                             right: inset)
        }
    
        override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
            var offsetAdjustment = CGFloat.max
            let horizontalOffset = proposedContentOffset.x + ((self.screenWidth - self.itemSize.width) / 2)
    
            let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: self.screenWidth, height: self.collectionViewHeight)
            var array = super.layoutAttributesForElementsInRect(targetRect)
    
            for layoutAttributes in array! {
                let itemOffset = layoutAttributes.frame.origin.x
                if (abs(itemOffset - horizontalOffset) < abs(offsetAdjustment)) {
                    offsetAdjustment = itemOffset - horizontalOffset
                }
            }
    
            return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
        }
    }