UICollectionView分类实现cell完全显示到屏幕上回调代理

日常需求开发中, 经常会遇到cell完全显示在屏幕上时做一些业务逻辑的需求,比如曝光埋点。

UICollectionView代理的并没有完全满足要求的回调方法。

- (void)collectionView:(UICollectionView*)collectionView willDisplayCell:(UICollectionViewCell*)cell forItemAtIndexPath:(NSIndexPath*)indexPath

上面方法是在cell被添加的时候回调,此时cell并没有显示在屏幕上,而且如果用户不继续滑,有可能cell不会显示。

所以可以利用分类实现这样的功能,以满足需求。

tableview如果要实现同样的功能的话道理一样。可以照猫画虎。

具体实现如下

UICollectionView+DispalyCell.h  文件

//  方案:

//  首先通过 代理collectionView:willDisplayCell:forItemAtIndexPath:收集将要显示的cell,添加到一个set内,

//  然后在scrollViewDidScroll: 回调方法内循环遍历set内的cell, 计算cell是否已全部显示在给定的区域内

//  如果已经全是显示,则回调代理, 并移除该cell, 移除后的cell可再次添加到数组里。

//

//  注意:

//  1:操作set时的线程安全问题。

//  2:快速滑动时的性能问题

//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@protocol CollectionViewDisplayDelegate <NSObject>

- (void)collectionView:(UICollectionView*)collectionView didDisplayCell:(UICollectionViewCell*)cell forItemAtIndexPath:(NSIndexPath*)indexPath;

@end

@interface UICollectionView (DispalyCell)

@property(nonatomic, weak) id<CollectionViewDisplayDelegate> displayDelegate;

@property(nonatomic, strong, readonly) NSMutableSet* cells; // cells that will be displayed

- (void)willDisplayCell:(UICollectionViewCell *)cell;

- (void)displayCell;

@end

NS_ASSUME_NONNULL_END


UICollectionView+DisplayCell.m 文件

#import "UICollectionView+DisplayCell.h"

#import <objc/runtime.h>

staticchar*k_cells ="k_cells";

staticchar*k_displayDelegate ="k_displayDelegate";

@implementation UICollectionView (DispalyCell)

- (void)setDisplayDelegate:(id<CollectionViewDisplayDelegate>)displayDelegate{

    objc_setAssociatedObject(self, k_displayDelegate, displayDelegate, OBJC_ASSOCIATION_ASSIGN);

}

- (id<CollectionViewDisplayDelegate>)displayDelegate{

    return objc_getAssociatedObject(self, k_displayDelegate);

}

- (NSMutableSet *)cells{

    NSMutableSet *set = objc_getAssociatedObject(self, k_cells);

    if(!set) {

        objc_setAssociatedObject(self, k_cells, [NSMutableSet set], OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    }else{

        returnset;

    }

    return objc_getAssociatedObject(self, k_cells);

}

- (void)willDisplayCell:(UICollectionViewCell *)cell{

    [self.cells addObject:cell];

}

- (void)displayCell{

    [self.cells enumerateObjectsUsingBlock:^(id  _Nonnullobj,BOOL*_Nonnullstop) {

        UICollectionViewCell*cell = obj;

        CGRect cell_r = [self convertRect:cell.frame toView:nil];   //nil 表示转换到window上

        CGRect collection_r = [self.superview convertRect:self.frame toView:nil];

        if(CGRectContainsRect(collection_r, cell_r)) {

            [self.cells removeObject:cell];

            SEL selector = @selector(collectionView:didDisplayCell:forItemAtIndexPath:);

            if([self.displayDelegate respondsToSelector:selector]) {

                [self.displayDelegate collectionView:self didDisplayCell:cell forItemAtIndexPath:[self indexPathForCell:cell]];

            }

        }

    }];

}

@end


下面是应用:

step1: 设置代理, 就像设置 delegate 或 dataSource一样。

self.collectionView.displayDelegate = self;

step2:  在下面的代理方法中调用分类的 willDisplayCell 方法。

- (void)collectionView:(UICollectionView*)collectionView willDisplayCell:(UICollectionViewCell*)cell forItemAtIndexPath:(NSIndexPath*)indexPath{

        [collectionView willDisplayCell:cell];

}

step3:   然后在scrollViewDidScroll中调用displayCell。

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{

// 这里做一下过滤, 也可以不过滤, 视具体情况而定

    if(self.collectionView == scrollView) {

        [self.collectionView displayCell];

    }

}

step4:  实现回调

- (void)collectionView:(UICollectionView*)collectionView didDisplayCell:(UICollectionViewCell*)cell forItemAtIndexPath:(NSIndexPath*)indexPath{

    // 在这里处理业务逻辑

}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • """1.个性化消息: 将用户的姓名存到一个变量中,并向该用户显示一条消息。显示的消息应非常简单,如“Hello ...
    她即我命阅读 8,593评论 0 5
  • 为了让我有一个更快速、更精彩、更辉煌的成长,我将开始这段刻骨铭心的自我蜕变之旅!从今天开始,我将每天坚持阅...
    李薇帆阅读 6,049评论 0 3
  • 似乎最近一直都在路上,每次出来走的时候感受都会很不一样。 1、感恩一直遇到好心人,很幸运。在路上总是...
    时间里的花Lily阅读 5,258评论 0 2
  • 1、expected an indented block 冒号后面是要写上一定的内容的(新手容易遗忘这一点); 缩...
    庵下桃花仙阅读 3,621评论 0 1
  • 一、工具箱(多种工具共用一个快捷键的可同时按【Shift】加此快捷键选取)矩形、椭圆选框工具 【M】移动工具 【V...
    墨雅丫阅读 3,582评论 0 0