How to create a Horizontal collection view like AIRBNB (Auto select index path on slide)

98 Views Asked by At

Sample video of AIRBNB APP

I implemented logic in func scrollViewDidScroll(_ scrollView: UIScrollView) but it is not working properly.

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    
    let principal = scrollView.contentSize.width - scrollView.frame.width
    let progress = scrollView.contentOffset.x / principal
    var progresss = max(0, min(1, progress))
    progressBar.setProgress(Float(progresss), animated: true)
    
    new = Int((CGFloat(arrayTagBasedFilter.count)) * progresss)
    new = Int(max(0, min(arrayTagBasedFilter.count-1, new)))
    let newIndex = IndexPath(item: new, section: 0)
    
    if let selectedIndexForFilter = selectedIndexForFilter
    {
        if let cell = collectionViewFilter.cellForItem(at: selectedIndexForFilter) as? BoostFilterCVCell
        {
            cell.lblTitle.textColor = .black.withAlphaComponent(0.5)
        }
    }
    
    if let cell = collectionViewFilter.cellForItem(at: newIndex) as? BoostFilterCVCell
    {
        selectedIndexForFilter = newIndex
        cell.lblTitle.textColor = .black
        progressView.frame = CGRect(origin: CGPoint(x: cell.frame.origin.x, y: collectionViewFilter.frame.origin.y - 50),
                                    size: CGSize(width: cell.frame.width, height: 1))
    }
}
1

There are 1 best solutions below

1
Aaron Wojnowski On

I was able to achieve this using the visibleCells method of UICollectionView. Here is an example using colored cells, where the "highlighted" cell has its alpha transparency reduced to 25%.

example-image

This example is in Objective-C, but you should be able to convert it to Swift fairly easily.

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
    void (^animateCellAlpha)(__kindof UICollectionViewCell *cell, CGFloat alpha) = ^(__kindof UICollectionViewCell *cell, CGFloat alpha) {
        [UIView animateWithDuration:0.25 animations:^{
            [cell setAlpha:alpha];
        }];
    };
    void (^highlightCell)(__kindof UICollectionViewCell *cell) = ^(__kindof UICollectionViewCell *cell) {
        animateCellAlpha(cell, 0.25);
    };
    void (^unhighlightCell)(__kindof UICollectionViewCell *cell) = ^(__kindof UICollectionViewCell *cell) {
        animateCellAlpha(cell, 1.0);
    };
    
    // fetch your collection view
    
    UICollectionView * const collectionView = (UICollectionView *)scrollView;
    
    // get the visible cells sorted by X value
    
    NSArray <__kindof UICollectionViewCell *> * const visibleCells = [[collectionView visibleCells] sortedArrayUsingComparator:^NSComparisonResult(__kindof UICollectionViewCell * _Nonnull obj1, __kindof UICollectionViewCell * _Nonnull obj2) {
        return [@(CGRectGetMinX([obj1 frame])) compare:@(CGRectGetMinX([obj2 frame]))];
    }];
    
    // determine which cell should or should not be highlighted
    
    BOOL __block didHighlightCell = NO;
    [visibleCells enumerateObjectsUsingBlock:^(__kindof UICollectionViewCell * _Nonnull cell, NSUInteger idx, BOOL * _Nonnull stop) {
        if (didHighlightCell) {
            // we do not want to highlight cells if a cell has already been highlighted
            unhighlightCell(cell);
            return;
        }
        
        // only highlight the cell if more than 50% of it is visible
        
        CGRect const frame = [[self view] convertRect:[cell frame] fromView:[cell superview]];
        if (CGRectGetMinX(frame) + CGRectGetWidth(frame) > CGRectGetWidth(frame) * 0.50) {
            highlightCell(cell);
            didHighlightCell = YES;
        } else {
            unhighlightCell(cell);
        }
    }];
    
}