封装了一个iOS联动滚动效果

效果图

实现逻辑和原理

就是在 didEndDisplayingCell 方法中通过indexPathsForVisibleItems 接口获取当前可见的cell对应的indexPath, 然后获取到item最小的那一个,即可,同时,还要在 willDisplayCell 方法中直接设置标题的选中属性,否则

由于重用机制,导致选中的展示错乱

代码

//
//  LBLinkedContentView.m
//  LBTwoLinkedScrollingCollectionView
//
//  Created by mac on 2024/6/25.
//

#import "LBLinkedContentView.h"
#import "LBLinkedContentViewTittleCell.h"
#import "LBLinkedContentViewContentCell.h"

@interface LBLinkedContentView () <UICollectionViewDelegate, UICollectionViewDataSource>

@property (nonatomic, strong) UICollectionView *titleView;
@property (nonatomic, strong) UICollectionView *contentView;

@property (nonatomic, strong) NSMutableArray *titleArray;
@property (nonatomic, strong) NSMutableArray *contentArray;

@property (nonatomic, strong) NSIndexPath *selectedGroupIndex;

@end

@implementation LBLinkedContentView

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        [self configData];
        [self setUpUI];
    }
    return self;
}

- (void)setUpUI
{
    [self addSubview:self.titleView];
    [self addSubview:self.contentView];
    [self.titleView reloadData];
    [self.contentView reloadData];
    self.selectedGroupIndex = [NSIndexPath indexPathForRow:0 inSection:0];
    LBLinkedContentViewTittleCell *titleCell = [self.titleView cellForItemAtIndexPath:self.selectedGroupIndex];
    titleCell.selected = YES;
}

#pragma mark - configData

- (void)configData
{
    for (int i = 0; i < 10; i ++)  {
        NSString *title = [NSString stringWithFormat:@"%d",i];
        [self.titleArray addObject:title];
        NSMutableArray *array = [NSMutableArray array];
        for (int j = 0; j < 10; j ++) {
            NSString *content = [NSString stringWithFormat:@"第%d分区第%d条", i,j];
            [array addObject:content];
        }
        [self.contentArray addObject:array];
    }
}

#pragma mark - data Delegate

- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    if (collectionView == self.contentView) {
        LBLinkedContentViewContentCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([LBLinkedContentViewContentCell class]) forIndexPath:indexPath];
        NSString *title = self.contentArray[indexPath.section][indexPath.item];
        [cell updateWithContent:title];
        return cell;
    }
    
    LBLinkedContentViewTittleCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([LBLinkedContentViewTittleCell class]) forIndexPath:indexPath];
    [cell updateWithIndexPath:indexPath];
    return cell;
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    if (collectionView == self.titleView) {
        return 1;
    }
    return self.contentArray.count;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 10;
}


- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
    if (collectionView == self.titleView) {
        if (self.selectedGroupIndex && [self.selectedGroupIndex compare:indexPath] == NSOrderedSame) {
            cell.selected = YES;
        } else {
            cell.selected = NO;
        }
    }
}

- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
    if (collectionView == self.contentView) {
        [self handleGroupViewWithIndex:nil];
    }
}

#pragma mark - private

- (void)handleGroupViewWithIndex:(NSIndexPath *)indexPathCell
{
    NSArray <NSIndexPath *> *visibleIndexPaths = [self.contentView indexPathsForVisibleItems];
    if (!visibleIndexPaths.count) {
        return;
    }
    NSInteger section = indexPathCell ? indexPathCell.section : [self.contentView numberOfSections] - 1;
    for (NSIndexPath *indexPath in visibleIndexPaths) {
        if (indexPath.section < section) {
            section = indexPath.section;
        }
    }
    NSIndexPath *groupIndexPath = [NSIndexPath indexPathForItem:section inSection:0];
    if(self.selectedGroupIndex && [self.selectedGroupIndex compare:groupIndexPath] != NSOrderedSame) {
        LBLinkedContentViewTittleCell *cell = [self.titleView cellForItemAtIndexPath:self.selectedGroupIndex];
        cell.selected = NO;
        self.selectedGroupIndex = groupIndexPath;
        LBLinkedContentViewTittleCell *titleCell = [self.titleView cellForItemAtIndexPath:groupIndexPath];
        titleCell.selected = YES;
        [self.titleView scrollToItemAtIndexPath:groupIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];
    }
}

#pragma mark - lazy load

- (UICollectionView *)titleView
{
    if (!_titleView) {
        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
        layout.minimumLineSpacing = 29;
        layout.minimumInteritemSpacing = 29;
        layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        layout.itemSize = CGSizeMake(40, 50);
        _titleView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), 60) collectionViewLayout:layout];
        [_titleView registerClass:[LBLinkedContentViewTittleCell class] forCellWithReuseIdentifier:NSStringFromClass([LBLinkedContentViewTittleCell class])];
        _titleView.delegate = self;
        _titleView.dataSource = self;
    }
    return _titleView;
}

- (UICollectionView *)contentView
{
    if (!_contentView) {
        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
        layout.minimumLineSpacing = 10;
        layout.minimumInteritemSpacing = 10;
        layout.itemSize = CGSizeMake(100, 80);
        layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        layout.sectionInset = UIEdgeInsetsMake(0, 40, 0, 40);
        _contentView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 80, CGRectGetWidth(self.bounds), 80) collectionViewLayout:layout];
        [_contentView registerClass:[LBLinkedContentViewContentCell class] forCellWithReuseIdentifier:NSStringFromClass([LBLinkedContentViewContentCell class])];
        _contentView.delegate = self;
        _contentView.dataSource = self;
        _contentView.backgroundColor = [UIColor yellowColor];
    }
    return _contentView;
}

- (NSMutableArray *)titleArray
{
    if (!_titleArray) {
        _titleArray = [NSMutableArray array];
    }
    return _titleArray;
}

- (NSMutableArray *)contentArray
{
    if (!_contentArray) {
        _contentArray = [NSMutableArray array];
    }
    return _contentArray;
}

@end

link

相关推荐
依旧风轻14 小时前
如何在应用运行时定期监控内存使用情况
ios·swift·内存优化
程序员老刘·14 小时前
如何评价Flutter?
android·flutter·ios
502胶水20517 小时前
腾讯地图异步调用
开发语言·ios·swift
刘小哈哈哈19 小时前
iOS UITableView自带滑动手势和父视图添加滑动手势冲突响应机制探索
macos·ios·cocoa
分享者花花19 小时前
恢复出厂设置后如何从 iPhone 恢复数据
windows·macos·ios·智能手机·excel·cocoa·iphone
1024小神20 小时前
SwiftUI中List的liststyle样式及使用详解添加、移动、删除、自定义滑动
ios·swiftui·swift
Lik102421 小时前
ReactNative如何实现沉浸式状态栏及渐变色Header【兼容Android和iOS】
android·react native·ios
Geeker551 天前
适用于 Windows的 5 个最佳 PDF 转 Word 转换器
ios·智能手机·pdf·电脑·word·手机·iphone
勤劳兔码农1 天前
iOS开发新手教程:Swift语言与Xcode工具链
ios·xcode·swift
<花开花落>1 天前
iOS App 测试环境升级,遇到的问题以及解决方法
macos·ios·appium